﻿Imports System
Imports System.Threading
Imports System.Collections
Imports System.Collections.Generic

Imports System.Diagnostics

#Region "LockType"
	<CLSCompliant(True)> _
	Public Enum LockType
			Read
			Write
			TryRead
			TryWrite
	End Enum
#End Region

#Region "LockObject"
	''' <summary>
	'''   Lock object to be used in a Using/End Using block.
	'''     This reduces code complexity by removing
	'''     Try/Finally/End Try blocks.
	''' 
	'''   It is also designed so it does not get allocated
	'''     each time it is used.  This eliminates excessively
	'''     making new items and garbage collecting them.
	''' </summary>
	''' <remarks>
	'''   // So instead of:
	''' 
	'''   Try
	'''     Lock.LockForWriting()
	''' 
	'''     // Perform thread safe code.
	'''   Finally
	'''     Lock.UnlockForWriting()
	'''   End Try
	''' 
	'''   // You would have:
	''' 
	'''   Using WriteLock As IDisposable = Lock.GetWriteLock()
	''' 
	'''   End Using
	''' 
	'''   // Where Lock.GetWriteLock() returns this LockObject.
	''' </remarks>
	<CLSCompliant(True)> _
	Public Class LockObject
		Implements IDisposable

		#Region "Members"
			Private _List     As IComplexReadWriteLocker
			Private _LockType As LockType
		#End Region

		#Region "Constructor"
			Public Sub New(__list As IComplexReadWriteLocker, __lockType As LockType)
				_List          = __list
				_LockType      = __lockType
			End Sub
		#End Region

		#Region "Methods"
			Public Function GetLock() As LockObject
				If _List IsNot Nothing Then
					Select Case _LockType
						Case LockType.Read
							_List.LockForReading()
						Case LockType.Write
							_List.LockForWriting()
						Case LockType.TryRead
							_List.TryLockForReading()
						Case LockType.TryWrite
							_List.TryLockForWriting()
					End Select
				End If

				Return Me
			End Function

			Protected Overridable Sub Dispose(disposing As Boolean)
				If disposing Then
					' Sends an event to the list that this lock has been disposed.
					If _List IsNot Nothing Then
						Select Case _LockType
							Case LockType.Read
								_List.UnlockForReading()
							Case LockType.Write
								_List.UnlockForWriting()
							Case LockType.TryRead
								_List.UnlockForReading()
							Case LockType.TryWrite
								_List.UnlockForWriting()
						End Select
					End If
				End If
			End Sub

			Public Sub Dispose() _
				Implements IDisposable.Dispose

				Dispose(True)
				GC.SuppressFinalize(Me)
			End Sub
		#End Region
	End Class
#End Region

#Region "Double-Integer Hashtable"
	''' <summary>
	'''   A wrapper designed to be used when accessing
	'''     <see>IdBasedReferenceCounter</see> Properties and Methods
	'''     while enumerating over it.
	''' 
	'''   Since it uses locking, access any Property or Method without
	'''     using this wrapper will cause deadlocks!
	'''   But if you use this wrapper outside of Enumerating over this
	'''     collection, accessing these members will not be thread-safe!
	''' 
	'''   So only use DirectCast([IdBasedReferenceCounter Object], IdBasedReferenceCounterIterWrap)
	'''     within for-each loops involving IdBasedReferenceCounter.
	''' </summary>
	Public Interface IdBasedReferenceCounterIterWrap
		ReadOnly Property Count As Integer
	End Interface

	''' <summary>
	'''   A reference counter for many keys having thread-safety in mind.
	'''     Basically, you can only increment and decrement a value based on
	'''     a given key.  And for this class, the key is an integer.
	''' 
	'''   But this isn't normal reference counting.  It takes into consideration
	'''     the number of threads accessing it.  And if it isn't parallel enough,
	'''     it expand itself internally so it performs well across many threads.
	''' 
	'''   If a key has a reference counting value of zero, it does not exist
	'''     in this collection.  But if you look to see what value it has, it
	'''     will return zero and act like it does exist.  But this zero valued
	'''     key will not be included in Count or take up any space.
	''' 
	'''   So to remove a key, all you need to do is decrement it to zero and
	'''     the space it takes will be removed.
	''' 
	'''   It supports does support decrementing below zero.
	''' 
	'''   TODO:  Get it to be resizeable based on how much thread waiting
	'''            is occuring, and its size.
	''' </summary>
	''' <remarks>
	'''   I use this for keeping track of ManagedThreadId's.  It could be
	'''     used for other purposes, such as reference counting based on any
	'''     Object using GetHashValue(), but for now it is only optimized for this.
	''' 
	'''   When cast as an ICollection, Add and Remove both call the function <see>[Set]</see>.
	'''     If the value is 0, then it gets removed. Otherwise, it gets set or added.
	''' 
	'''   -------------------------------------------------------------------------
	''' 
	'''   This collection internally uses radix buckets to increase parallelism and
	'''     decrease search times.  The buckets use arrays instead of more advanced
	'''     collections like hash tables or binary trees because it is assumed that
	'''     the collections in each bucket will be kept small.  So using an advanced
	'''     heristic algorithm like in hash tables would incure more overhead than
	'''     simply searching the list linearly.
	''' 
	'''   By radix bucket, I mean that there is a static collection of size X.
	'''      And X is for example ten, as there are ten (0-9) digits in each
	'''      decimal place.  So the last number in the value is used to determine
	'''      which array it will be put into.
	''' 
	'''   And basically it a way to seperates a larger array into many smaller arrays.
	'''     This decreases search time by a constant X, as well as it allows changing,
	'''     two seperate buckets at the same time (such as adding or removing items).
	''' 
	'''   The disadvantage is that unused buckets will take up space.  But compared
	'''     to hash tables, this extra needed space should be small in comparison.
	''' </remarks>
	Public Class IdBasedReferenceCounter
		Implements ICollection(Of KeyValue), _
		           IdBasedReferenceCounterIterWrap

		#Region "Constants"
			' Effects the size of the buckets, and is used for the second bucket.
			Private Const BucketBits As Integer = 4
			' Size of the bucket.  Must be power-of-two and equal to 2 ^ BucketBits.
			Private Const BucketSize As Integer = CInt(2 ^ BucketBits)
			' BucketSize - 1.  Since BucketSize is power-of-two, this = all 1's in binary.
			Private Const BucketMask As Integer = BucketSize - 1

			' Used to determine how many loops a spin-lock should do before it sleeps.
			Friend Shared SpinLockWait As Integer  = 64 * (Environment.ProcessorCount + 1)
			' Used to determine when a bucket needs expanded due to too many threads waiting to access it.
			Friend Shared MaxThreashold As Integer = 32 \ Environment.ProcessorCount + 2
			' Determines if this has more than one thread that can run at the same time.
			Friend Shared MultiProcessor As Boolean = Environment.ProcessorCount > 1
		#End Region

		#Region "Classes"
			Public Class KeyValue
				Public Key   As Integer
				Public Value As Integer

				Public Sub New(__newKey As Integer, __newValue As Integer)
					Key   = __newKey
					Value = __newValue
				End Sub
			End Class

			Private Class BucketTable
				Public Table(BucketSize) As List(Of KeyValue)

				Public WriteSync(BucketSize)   As Integer
				Public ReadSync(BucketSize)    As Integer
				Public UpgradeSync(BucketSize) As Integer
			End Class

			''' <summary>
			'''   Enumerator which iterates through all the buckets in this collection.
			''' 
			'''   It uses a read-lock to guarantee the data being iterated over doesn't change.
			'''     But the unique thing about the locking is that it only read locks on
			'''     the bucket which is being read over.  So changing other buckets is possible.
			''' </summary>
			Private Class Iterator
				Implements IEnumerator(Of KeyValue)

				#Region "Members"
					Private _BucketMap As IdBasedReferenceCounter

					Private _First  As Integer
					Private _Second As Integer
					Private _Index  As Integer
					
					Private _PerformLocking As Boolean
				#End Region

				#Region "Constuctors"
					Public Sub New(__bucketMap As IdBasedReferenceCounter, Optional __performLocking As Boolean = True)
						' Is valid after it is incremented the first time.
						_Index = -1
						_PerformLocking = __performLocking
						
						__bucketMap.BeginReadSpinLock()

						If __performLocking AndAlso 0 < __bucketMap._CurrentBucketSize Then
							' Starts read-locking on the first bucket.
							__bucketMap.BeginReadSpinLock(0, 0)
						End If
						
						_BucketMap = __bucketMap
					End Sub
				#End Region

				#Region "Properties"
					Public ReadOnly Property Current As KeyValue _
						Implements IEnumerator(Of KeyValue).Current

						Get
							If _First >= _BucketMap._CurrentBucketSize OrElse _
								 _BucketMap._Table(_First).Table(_Second) Is Nothing Then

								Return New KeyValue(0, 0)
							End If

							Return _BucketMap._Table(_First).Table(_Second)(_Index)
						End Get
					End Property

					Private ReadOnly Property CurrentValue As Object _
						Implements IEnumerator.Current

						Get
							Return Current
						End Get
					End Property
				#End Region

				#Region "Methods"
					Public Function MoveNext() As Boolean _
						Implements IEnumerator.MoveNext

						Dim CurrentBucketSize As Integer = _BucketMap._CurrentBucketSize

						If _First >= CurrentBucketSize Then
							Return False
						End If

						Dim Bucket As List(Of KeyValue) = _BucketMap._Table(_First).Table(_Second)
						_Index += 1

						' Iterates through any zero valued buckets if a bucket is found.
						If Bucket IsNot Nothing Then
							' If a zero indexed bucket hasn't been removed yet, skip it.
							While (_Index < Bucket.Count AndAlso Bucket(_Index).Value = 0)
								_Index += 1
							End While

							If _Index >= Bucket.Count Then
								Bucket = Nothing
							Else
								Return True
							End If
						End If

						' We are going to be changing buckets, so _Index = first index.
						_Index = 0

						Do
							If _PerformLocking Then							
								' End previous buckets read locking.
								If _First < CurrentBucketSize Then
									_BucketMap.EndReadSpinLock(_First, _Second)
								End If
							End If
							
							_Second += 1

							If _Second >= CurrentBucketSize Then
								_Second = 0
								_First += 1
							End If
							
							If _PerformLocking Then
								' Begin next buckets' locking if it hasn't past the last bucket.
								If _First < CurrentBucketSize Then
									_BucketMap.BeginReadSpinLock(_First, _Second)
								Else
									Exit Do
								End If
							End If

							If Bucket IsNot Nothing AndAlso Bucket.Count > 0 Then
								Exit Do
							End If

							Bucket = _BucketMap._Table(_First).Table(_Second)
						Loop While True

						' If the new bucket's beginning value is zero,
						'   because it hasn't been removed yet, move to
						'   the next position by re-calling this Method.
						If Bucket Is Nothing Then
							Return False
						ElseIf Bucket.Count = 0 OrElse Bucket(0).Value = 0 Then
							Return MoveNext()
						End If

						Return True
					End Function

					Public Sub Reset() _
						Implements IEnumerator.Reset
						
						If _PerformLocking Then
							If _First < _BucketMap._CurrentBucketSize Then
								' Ends read-locking on the last bucket this iterator was in.
								_BucketMap.EndReadSpinLock(_First, _Second)
							End If
						End If

						_First  = 0
						_Second = 0
						_Index  = -1
						
						If _PerformLocking Then
							If _First < _BucketMap._CurrentBucketSize Then
								' Ends read-locking on the last bucket this iterator was in.
								_BucketMap.BeginReadSpinLock(_First, _Second)
							End If
						End If
					End Sub

					' Ends reading, removes reference to _BucketMap, and
					'   tells .NET that there is no need to call the destructor.
					Public Sub Dispose() _
						Implements IDisposable.Dispose
						
						If _PerformLocking Then
							If _First < _BucketMap._CurrentBucketSize Then
								' Ends read-locking on the last bucket this iterator was in.
								_BucketMap.EndReadSpinLock(_First, _Second)
							End If

							_BucketMap.BeginReadSpinLock()
						End If
						
						_BucketMap = Nothing

						GC.SuppressFinalize(Me)
					End Sub
				#End Region
			End Class
			
			Private Class IteratorCollection
				Implements IEnumerable(Of KeyValue)
				
				Dim _Iter As Iterator
				
				Public Sub New(__bucketCollection As IdBasedReferenceCounter)
					_Iter = New Iterator(__bucketCollection)
				End Sub
				
				Public Function GetEnumerator() As IEnumerator(Of KeyValue) _
					Implements IEnumerable(Of KeyValue).GetEnumerator
					
					Return _Iter
				End Function
				
				Private Function GetEnumeratorValue() As IEnumerator _
					Implements IEnumerable.GetEnumerator
					
					Return _Iter
				End Function
			End Class
		#End Region

		#Region "Members"
			Private _CurrentBucketBits As Integer = BucketBits
			Private _CurrentBucketSize As Integer = BucketSize
			Private _CurrentBucketMask As Integer = BucketMask

			' Tracks the maximum number of threads waiting on another thread
			'   to finish inserting or removing a key/value pair from any bucket.
			Private _ThreadingConflicts As Integer

			' Used to lock the radix buckets so it can be resized.
			Private _WriteSync          As Integer
			Private _ReadSync           As Integer
			Private _UpgradeSync        As Integer

			' Size of this collection.
			Private _Count              As Integer

			' Contents of this collection sorted into buckets.  Below represents an individual bucket.
			'   _Table(Key MOD BucketSize).Table((Key \ BucketSize) MOD BucketSize) == [Array of KeyValuePair]
			Private _Table(BucketSize) As BucketTable
		#End Region

		#Region "Constructors"
			Public Sub New()
				For Index As Integer = 0 To BucketSize - 1
					_Table(Index) = New BucketTable()
				Next
			End Sub
		#End Region

		#Region "Properties"
			Public Default ReadOnly Property Peek(key As Integer) As Integer
				Get
					Try
						BeginReadSpinLock()

						' These are only thread-safe in a global ReadSpinLock.
						Dim FirstHexPlace  As Integer = key And BucketMask
						Dim SecondHexPlace As Integer = (key >> BucketBits) And BucketMask

						Try
							BeginReadSpinLock(FirstHexPlace, SecondHexPlace)

							' Getting this bucket is only thread safe in a local ReadSpinLock.
							Dim Bucket As List(Of KeyValue) = _
								_Table(FirstHexPlace).Table(SecondHexPlace)

							If Bucket Is Nothing Then
								Return 0
							End If

							For Index As Integer = 0 To Bucket.Count - 1
								If Bucket(Index).Key = key Then
									Return Bucket(Index).Value
								End If
							Next

							Return 0
						Finally
							EndReadSpinLock(FirstHexPlace, SecondHexPlace)
						End Try
					Finally
						EndReadSpinLock()
					End Try
				End Get
			End Property

			Public ReadOnly Property Count As Integer _
				Implements ICollection(Of KeyValue).Count

				Get
					Dim VolatileCount As Integer
					VolatileCount = _Count
					Thread.MemoryBarrier()

					Return VolatileCount
				End Get
			End Property

			Private ReadOnly Property ThreadUnsafeCount() As Integer _
				Implements IdBasedReferenceCounterIterWrap.Count

				Get
					Return Count
				End Get
			End Property

			Private ReadOnly Property IsReadOnly As Boolean _
				Implements ICollection(Of KeyValue).IsReadOnly

				Get
					Return False
				End Get
			End Property
		#End Region

		#Region "Methods"
			#Region "Contains/CopyTo"
				Private Function Contains(item As KeyValue) As Boolean _
					Implements ICollection(Of KeyValue).Contains

					Return Peek(item.Key) = item.Value
				End Function

				Private Sub CopyTo(array() As KeyValue, arrayIndex As Integer) _
					Implements ICollection(Of KeyValue).CopyTo

					Dim Index As Integer = 0

					For Each Item As KeyValue In Me
						array(Index) = Item

						Index = Index + 1

						If Index >= array.Length OrElse _
							(arrayIndex > 0 AndAlso Index > arrayIndex) Then

							Exit For
						End If						
					Next
				End Sub
			#End Region

			#Region "GetEnumerator"
				Private Function GetEnumerator() As IEnumerator(Of KeyValue) _
					Implements IEnumerable(Of KeyValue).GetEnumerator

					Return New Iterator(Me)
				End Function

				Private Function GetEnumeratorValue() As IEnumerator _
					Implements IEnumerable.GetEnumerator

					Return GetEnumerator()
				End Function
			#End Region

			#Region "Global Spinlock"
				''' <summary>
				'''   Begins looping while another instance exists.
				'''     Otherwise, this continues, initializing itself
				'''     as the spinlock so no other spinlocks can continue.
				''' </summary>
				''' <remarks>
				'''   This is not recursive!  In most cases, you will
				'''     want to look at this code and implement your own
				'''     spinlock with its own integer variable.
				''' </remarks>
				Private Sub BeginReadSpinLock()
					Dim SpinWait As Integer = 1
					Dim VolatileWriteSync As Integer

					While True
						VolatileWriteSync = _WriteSync
						Thread.MemoryBarrier()

						If (VolatileWriteSync <= 0) Then
							Exit While
						End If

StartLocalRead:
						If SpinWait < 11 AndAlso MultiProcessor Then
							Thread.SpinWait(20 * SpinWait)
						ElseIf (SpinWait < 16) Then
								Thread.Sleep(0)
						Else
								Thread.Sleep(1)
						End If

						SpinWait += 1
					End While

					Interlocked.Increment(_ReadSync)

					VolatileWriteSync = _WriteSync
					Thread.MemoryBarrier()

					If VolatileWriteSync > 0 Then
						Interlocked.Decrement(_ReadSync)
						GoTo StartLocalRead
					End If
				End Sub

				''' <summary>
				'''   Ends locking and allows another spinlock to take over.
				''' </summary>
				''' <remarks>
				'''   This is not recursive!  In most cases, you will
				'''     want to look at this code and implement your own
				'''     spinlock with its own integer variable.
				''' </remarks>
				Private Sub EndReadSpinLock()
					Interlocked.Decrement(_ReadSync)
				End Sub

				''' <summary>
				'''   Converts a read spinlock into a write spinlock for a duration of time.
				''' </summary>
				''' <remarks>
				'''   This is not recursive!  It also must only be used within a read lock.
				'''     It cannot contain a write lock, as this is a write lock.
				'''     Otherwise, this will cause deadlocks.
				''' </remarks>
				Private Sub BeginUpgradeReadToWriteSpinLock()
					Interlocked.Increment(_UpgradeSync)

					Dim SpinWait As Integer = 1

					While (Interlocked.CompareExchange(_WriteSync, 1,  0) > 0)
						If SpinWait < 11 AndAlso MultiProcessor Then
							Thread.SpinWait(20 * SpinWait)
						ElseIf (SpinWait < 16) Then
								Thread.Sleep(0)
						Else
								Thread.Sleep(1)
						End If

						SpinWait += 1
					End While

					SpinWait = 1

					Dim VolatileReadSync    As Integer
					Dim VolatileUpgradeSync As Integer

					While True
						VolatileReadSync = _ReadSync
						Thread.MemoryBarrier()

						VolatileUpgradeSync = _UpgradeSync
						Thread.MemoryBarrier()

						If VolatileReadSync = VolatileUpgradeSync Then
							Exit While
						End If

						If SpinWait < 11 AndAlso MultiProcessor Then
							Thread.SpinWait(20 * SpinWait)
						ElseIf (SpinWait < 16) Then
								Thread.Sleep(0)
						Else
								Thread.Sleep(1)
						End If

						SpinWait += 1
					End While
				End Sub

				''' <summary>
				'''   Ends an upgraded spinlock.
				''' </summary>
				Private Sub EndUpgradeReadToWriteSpinLock()
					Dim VolatileUpgradeSync As Integer

					VolatileUpgradeSync = _UpgradeSync
					Thread.MemoryBarrier()					
					_ReadSync = _UpgradeSync

					Interlocked.Decrement(_UpgradeSync)
					Interlocked.CompareExchange(_WriteSync, 0,  1)
				End Sub

				''' <summary>
				'''   Begins looping while another instance exists.
				'''     Otherwise, this continues, initializing itself
				'''     as the spinlock so no other spinlocks can continue.
				''' </summary>
				''' <remarks>
				'''   This is not recursive!  In most cases, you will
				'''     want to look at this code and implement your own
				'''     spinlock with its own integer variable.
				''' </remarks>
				Private Sub BeginWriteSpinLock()
					BeginReadSpinLock()
					BeginUpgradeReadToWriteSpinLock()
				End Sub

				''' <summary>
				'''   Ends locking and allows another spinlock to take over.
				''' </summary>
				''' <remarks>
				'''   This is not recursive!  In most cases, you will
				'''     want to look at this code and implement your own
				'''     spinlock with its own integer variable.
				''' </remarks>
				Private Sub EndWriteSpinLock()
					EndUpgradeReadToWriteSpinLock()
					EndReadSpinLock()
				End Sub
			#End Region

			#Region "Bucket SpinLock"
				''' <summary>
				'''   Begins looping while another instance exists.
				'''     Otherwise, this continues, initializing itself
				'''     as the spinlock so no other spinlocks can continue.
				''' </summary>
				''' <remarks>
				'''   This is not recursive!  In most cases, you will
				'''     want to look at this code and implement your own
				'''     spinlock with its own integer variable.
				''' </remarks>
				Private Sub BeginReadSpinLock(firstIndex As Integer, secondIndex As Integer)
					Dim SpinWait As Integer = 1
					Dim Table    As BucketTable = _Table(firstIndex)
					Dim VolatileTableWriteSync As Integer

					While True
						VolatileTableWriteSync = Table.WriteSync(secondIndex)
						Thread.MemoryBarrier()

						If VolatileTableWriteSync <= 0 Then
							Exit While
						End If
StartLocalRead:
						If SpinWait < 11 AndAlso MultiProcessor Then
							Thread.SpinWait(20 * SpinWait)
						ElseIf (SpinWait < 16) Then
								Thread.Sleep(0)
						Else
								Thread.Sleep(1)
						End If

						SpinWait += 1
					End While

					Interlocked.Increment(Table.ReadSync(secondIndex))

					VolatileTableWriteSync = Table.WriteSync(secondIndex)
					Thread.MemoryBarrier()

					If VolatileTableWriteSync > 0 Then
						Interlocked.Decrement(Table.ReadSync(secondIndex))
						GoTo StartLocalRead
					End If
				End Sub

				''' <summary>
				'''   Ends locking and allows another spinlock to take over.
				''' </summary>
				''' <remarks>
				'''   This is not recursive!  In most cases, you will
				'''     want to look at this code and implement your own
				'''     spinlock with its own integer variable.
				''' </remarks>
				Private Sub EndReadSpinLock(firstIndex As Integer, secondIndex As Integer)
					Interlocked.Decrement(_Table(firstIndex).ReadSync(secondIndex))
				End Sub

				''' <summary>
				'''   Converts a read spinlock into a write spinlock for a duration of time.
				''' </summary>
				''' <remarks>
				'''   This is not recursive!  It also must only be used within a read lock.
				'''     It cannot contain a write lock, as this is a write lock.
				'''     Otherwise, this will cause deadlocks.
				''' </remarks>
				Private Sub BeginUpgradeReadToWriteSpinLock(firstIndex As Integer, secondIndex As Integer)
					Interlocked.Increment(_Table(firstIndex).UpgradeSync(secondIndex))

					Dim SpinWait As Integer = 1
					Dim Table    As BucketTable = _Table(firstIndex)

					While (Interlocked.CompareExchange(Table.WriteSync(secondIndex), 1,  0) > 0)
						If SpinWait < 11 AndAlso MultiProcessor Then
							Thread.SpinWait(20 * SpinWait)
						ElseIf (SpinWait < 16) Then
								Thread.Sleep(0)
						Else
								Thread.Sleep(1)
						End If

						SpinWait += 1
					End While

					SpinWait = 1

					Dim VolatileTableReadSync    As Integer
					Dim VolatileTableUpgradeSync As Integer

					While True
						VolatileTableReadSync    = Table.ReadSync(secondIndex)
						Thread.MemoryBarrier()

						VolatileTableUpgradeSync = Table.UpgradeSync(secondIndex)
						Thread.MemoryBarrier()

						If VolatileTableReadSync = VolatileTableUpgradeSync Then
							Exit While
						End If

						If SpinWait < 11 AndAlso MultiProcessor Then
							Thread.SpinWait(20 * SpinWait)
						ElseIf (SpinWait < 16) Then
								Thread.Sleep(0)
						Else
								Thread.Sleep(1)
						End If

						SpinWait += 1
					End While
				End Sub

				''' <summary>
				'''   Ends an upgraded spinlock.
				''' </summary>
				Private Sub EndUpgradeReadToWriteSpinLock(firstIndex As Integer, secondIndex As Integer)
					Dim Table As BucketTable = _Table(firstIndex)

					Dim VolatileTableUpgradeSync As Integer
					VolatileTableUpgradeSync = _Table(firstIndex).UpgradeSync(secondIndex)
					Thread.MemoryBarrier()
					Table.ReadSync(secondIndex) = VolatileTableUpgradeSync

					Interlocked.Decrement(Table.UpgradeSync(secondIndex))
					Interlocked.CompareExchange(Table.WriteSync(secondIndex), 0,  1)
				End Sub

				''' <summary>
				'''   Begins looping while another instance exists.
				'''     Otherwise, this continues, initializing itself
				'''     as the spinlock so no other spinlocks can continue.
				''' </summary>
				''' <remarks>
				'''   This is not recursive!  In most cases, you will
				'''     want to look at this code and implement your own
				'''     spinlock with its own integer variable.
				''' </remarks>
				Private Sub BeginWriteSpinLock(firstIndex As Integer, secondIndex As Integer)
					BeginReadSpinLock(firstIndex, secondIndex)
					BeginUpgradeReadToWriteSpinLock(firstIndex, secondIndex)
				End Sub

				''' <summary>
				'''   Ends locking and allows another spinlock to take over.
				''' </summary>
				''' <remarks>
				'''   This is not recursive!  In most cases, you will
				'''     want to look at this code and implement your own
				'''     spinlock with its own integer variable.
				''' </remarks>
				Private Sub EndWriteSpinLock(firstIndex As Integer, secondIndex As Integer)
					EndUpgradeReadToWriteSpinLock(firstIndex, secondIndex)
					EndReadSpinLock(firstIndex, secondIndex)
				End Sub
			#End Region

			#Region "Increment/Decrement"
				Private Function InitializeBucket(key As Integer, firstHexPlace As Integer, secondHexPlace As Integer) As List(Of KeyValue)
					' This may get initialized when it doesn't need to be,
					'   but it is the only way to guarantee that CompareExchange
					'   works atomically.  Otherwise, more expensive locking would be needed.
					Dim NewBucket As New List(Of KeyValue)(New KeyValue() {New KeyValue(key, 0)})

					' Atomically initializes a bucket and sets up Bucket variable appropriately.
					'   Once a bucket gets initialized, the only way it can be de-initialized
					'   is when all the number of buckets get resized.
					If Interlocked.CompareExchange(_Table(FirstHexPlace).Table(SecondHexPlace), _
					                               NewBucket, Nothing) Is Nothing Then

						' Increases the size of this collection by 1.
						Interlocked.Increment(_Count)
						Return NewBucket
					Else
						Return _Table(FirstHexPlace).Table(SecondHexPlace)
					End If
				End Function

				Private Sub AddItem(bucket As List(Of KeyValue), key As Integer, value As Integer, _
				                    firstHexPlace As Integer, secondHexPlace As Integer)
					Try
						BeginUpgradeReadToWriteSpinLock(firstHexPlace, secondHexPlace)

						Bucket.Add(New KeyValue(key, value))

						' Increases the size of this collection by 1.
						Interlocked.Increment(_Count)
					Finally
						EndUpgradeReadToWriteSpinLock(firstHexPlace, secondHexPlace)
					End Try
				End Sub

				' In the future...
				'
				' Removing an item doesn't remove it from this collection.
				'   An internal garbage collector will remove it instead.
				Private Sub RemoveItem(bucket As List(Of KeyValue), index As Integer, _
				                       firstHexPlace As Integer, secondHexPlace As Integer)
					' TODO:  Implement garbage collector to buffer removing items.
					Try
						BeginUpgradeReadToWriteSpinLock(firstHexPlace, secondHexPlace)

						If Bucket(Index).Value = 0 Then
							Bucket.RemoveAt(Index)

							' Decreases the size of this collection by 1.
							Interlocked.Decrement(_Count)
						End If
					Finally
						EndUpgradeReadToWriteSpinLock(firstHexPlace, secondHexPlace)
					End Try
				End Sub
				
				Public Function LinearSearchForBucket(key As Integer) As Boolean
					For Each KeyValue As KeyValue In New IteratorCollection(Me)
						If KeyValue.Key = key Then
							Return True
						End If
					Next
					
					Return False
				End Function

				Public Function Increment(key As Integer) As Integer
					Try
						BeginReadSpinLock()

						' These are only thread-safe in a global ReadSpinLock.
						Dim FirstHexPlace  As Integer = key And BucketMask
						Dim SecondHexPlace As Integer = (key >> BucketBits) And BucketMask

						Try
							BeginReadSpinLock(FirstHexPlace, SecondHexPlace)

							' Getting this bucket is only thread safe in a local ReadSpinLock.
							Dim Bucket As List(Of KeyValue) = _
								_Table(FirstHexPlace).Table(SecondHexPlace)

							If Bucket Is Nothing Then
								' This initializes "_Table(FirstHexPlace).Table(SecondHexPlace)"
								'   and returns this bucket.
								'
								' The bucket is initialized with one KeyValue = {key, 0}.
								'   This is so the key will be found and value incremented below.
								Bucket = InitializeBucket(key, FirstHexPlace, SecondHexPlace)
							End If

							For Index As Integer = 0 To Bucket.Count - 1
								If Bucket(Index).Key = key Then
									Dim Value As Integer = Interlocked.Increment(Bucket(Index).Value)

									If Value = 0 Then
										' Called within a read lock. It will upgrade to write locking.
										RemoveItem(Bucket, Index, FirstHexPlace, SecondHexPlace)
									End If

									Return Value
								End If
							Next
							
							If LinearSearchForBucket(key) Then
								Dim X As Integer = 1
							End If
							
							' Called within a read lock. It will upgrade to write locking.
							AddItem(Bucket, key, 1, FirstHexPlace, SecondHexPlace)
						Finally
							EndReadSpinLock(FirstHexPlace, SecondHexPlace)
						End Try
					Finally
						EndReadSpinLock()
					End Try
					
					Return 1
				End Function

				Public Function Decrement(key As Integer) As Integer
					Try
						BeginReadSpinLock()

						' These are only thread-safe in a global ReadSpinLock.
						Dim FirstHexPlace  As Integer = key And BucketMask
						Dim SecondHexPlace As Integer = (key >> BucketBits) And BucketMask

						Try
							BeginReadSpinLock(FirstHexPlace, SecondHexPlace)

							' Getting this bucket is only thread safe in a local ReadSpinLock.
							Dim Bucket As List(Of KeyValue) = _
								_Table(FirstHexPlace).Table(SecondHexPlace)

							If Bucket Is Nothing Then
								' This initializes "_Table(FirstHexPlace).Table(SecondHexPlace)"
								'   and returns this bucket.
								'
								' The bucket is initialized with one KeyValue = {key, 0}.
								'   This is so the key will be found and value decremented below.
								Bucket = InitializeBucket(key, FirstHexPlace, SecondHexPlace)
							End If

							For Index As Integer = 0 To Bucket.Count - 1
								If Bucket(Index).Key = key Then
									Dim Value As Integer = _
										Interlocked.Decrement(Bucket(Index).Value)

									If Value = 0 Then
										' Called within a read lock. It will upgrade to write locking.
										RemoveItem(Bucket, Index, FirstHexPlace, SecondHexPlace)
									End If

									Return Value
								End If
							Next

							If LinearSearchForBucket(key) Then
								Dim X As Integer = 1
							End If
							
							' Called within a read lock. It will upgrade to write locking.
							AddItem(Bucket, key, -1, FirstHexPlace, SecondHexPlace)
						Finally
							EndReadSpinLock(FirstHexPlace, SecondHexPlace)
						End Try
					Finally
						EndReadSpinLock()
					End Try
					
					Return -1
				End Function
			#End Region

			#Region "Add/Remove/Clear"
				''' <summary>
				'''   This sets a reference count to a specific value.
				'''     If it is not equal to zero, it sets it or adds it.
				'''     Otherwise, Set removes the item!
				''' </summary>
				Private Sub Add(item As KeyValue) _
					Implements ICollection(Of KeyValue).Add

					[Set](item)
				End Sub

				Private Function Remove(item As KeyValue) As Boolean _
					Implements ICollection(Of KeyValue).Remove

					Return Not [Set](item)
				End Function

				Public Function [Set](item As KeyValue) As Boolean
					Try
						BeginReadSpinLock()

						' These are only thread-safe in a global ReadSpinLock.
						Dim FirstHexPlace  As Integer = item.Key And BucketMask
						Dim SecondHexPlace As Integer = (item.Key >> BucketBits) And BucketMask

						Try
							BeginReadSpinLock(FirstHexPlace, SecondHexPlace)

							' Getting this bucket is only thread safe in a local ReadSpinLock.
							Dim Bucket As List(Of KeyValue) = _
								_Table(FirstHexPlace).Table(SecondHexPlace)

							' If there is no bucket and value = 0, it is already set!
							If item.Value = 0 AndAlso Bucket Is Nothing Then
								Return True
							End If

							If Bucket Is Nothing Then
								' This initializes "_Table(FirstHexPlace).Table(SecondHexPlace)"
								'   and returns this bucket.
								'
								' The bucket is initialized with one KeyValue = {key, 0}.
								'   This is so the key will be found and value incremented below.
								Bucket = InitializeBucket(item.Key, FirstHexPlace, SecondHexPlace)
							End If

							For Index As Integer = 0 To Bucket.Count - 1
								If Bucket(Index).Key = item.Key Then
									If item.Value = 0 Then
										RemoveItem(Bucket, Index, FirstHexPlace, SecondHexPlace)

										Return False
									End If

									Thread.MemoryBarrier()
									Bucket(Index).Value = item.Value

									Return True
								End If
							Next

							If item.Value <> 0 Then
								AddItem(Bucket, item.Key, item.Value, FirstHexPlace, SecondHexPlace)

								Return True
							End If

							Return False
						Finally
							EndReadSpinLock(FirstHexPlace, SecondHexPlace)
						End Try
					Finally
						EndReadSpinLock()
					End Try
				End Function

				Public Sub Clear() _
					Implements ICollection(Of KeyValue).Clear

					Try
						BeginReadSpinLock()

						For FirstHexPlace As Integer = 0 To BucketSize - 1
							For SecondHexPlace As Integer = 0 To BucketSize - 1
								Try
									BeginWriteSpinLock(FirstHexPlace, SecondHexPlace)
								
									Dim Bucket As List(Of KeyValue) = _
										_Table(FirstHexPlace).Table(SecondHexPlace)

									If Bucket IsNot Nothing Then
										Dim BucketCount As Integer = 0

										For Index As Integer = 0 To Bucket.Count - 1
											If Bucket(Index).Value <> 0 Then
												BucketCount += 1
											End If
										Next

										' Clears the bucket so it doesn't take any space.
										_Table(FirstHexPlace).Table(SecondHexPlace) = Nothing

										' TODO:  Decrement Count by BucketCount in one atomic operation.
										While BucketCount > 0
											Interlocked.Decrement(Count)
											BucketCount -= 1
										End While
									End If
								Finally
									EndWriteSpinLock(FirstHexPlace, SecondHexPlace)
								End Try
							Next
						Next
					Finally
						EndReadSpinLock()
					End Try
				End Sub
			#End Region
		#End Region
	End Class
#End Region

#Region "Circular Thread Queue"
	''' <summary>
	'''   Circular non-blocking list that tracks locking.
	'''     Each item holds a list of threads, 
	''' </summary>
	''' <remarks>
	'''   This class keeps track of the beginning and ending,
	'''     and the current position is inbetween these nodes.
	''' 
	'''   Nodes can come after end and before start.
	''' 
	'''   When this happens, they are used as a buffer, which
	'''     allows them to be used when adding new nodes,
	'''     instead of actually 
	''' </remarks>
	Friend Class CircularThreadIdQueue
		#Region "Classes"
			Public Class Node
				' If this is a node setup for reading, this will be non-null.
				Public ReadingThreadIds As List(Of Integer)
				' Otherwise, WriteThreadId will be used for the single write thread.
				Public WritingThreadId As Integer

				Public [Next] As Node

				Public Sub New(__readingThreadIds As List(Of Integer), __next As Node)
					ReadingThreadIds = __readingThreadIds

					[Next] = __next
				End Sub

				Public Sub New(__writingThreadId As Integer, __next As Node)
					WritingThreadId = __writingThreadId

					[Next] = __next
				End Sub
			End Class
		#End Region

		#Region "Members"
			Private _Start As Node
			Private _End   As Node

			Private _Position As Node
		#End Region
	End Class
#End Region

#Region "SynchronizationLockException->DeadlockFoundException"
	<CLSCompliant(True)> _
	Public Class DeadlockFoundException
		Inherits SynchronizationLockException

		Public Sub New()
			MyBase.New()
		End Sub

		Public Sub New(message As String)
			MyBase.New(message)
		End Sub

		Public Sub New(message As String, innerException As Exception)
			MyBase.New(message, innerException)
		End Sub
	End Class
#End Region

#Region "ReadWriteLocker"
	''' <summary>
	'''   A stable wrapper around ReadWriteLocker which
	'''     allows the same thread to both lock it for
	'''     reading and writing.
	'''   It has a lot of provisions for preventing the
	'''     same thread from locking itself by automatically
	'''     handling the ReadLock to WriteLock Upgrade/Downgrade.
	''' </summary>
	''' <remarks>
	'''   <pre>
	'''   Example:
	''' 
	'''     Dim Locker As New ReadWriteLocker()
	'''     Dim ThreadUnsafeList As New List(Of Integer)()
	''' 
	'''     Try
	'''       Locker.LockForReading()
	''' 
	'''       ' Read something
	'''       Dim Size As Integer = ThreadUnsafeList.Count
	''' 
	'''       Try
	'''         Locker.LockForWriting()
	'''           ' Write something
	'''           ThreadUnsafeList.Add(5)
	'''       Finally
	'''         Locker.UnlockForWriting()
	'''       End Try
	''' 
	'''       MessageBox.Show(Me, "Size before: " - Size - ". Size now: " - ThreadUnsafeList.Count)
	'''     Finally
	'''       Locker.UnlockForReading()
	'''     End Try
	'''
	'''     ' Note:  This way makes a new Object each time it is used,
	'''     '        but in most situations, that is neglegable.
	'''     ' Or with using the IDisposable Objects:
	''' 
	'''     Dim Locker As New ReadWriteLocker()
	'''     Dim ThreadUnsafeList As New List(Of Integer)()
	''' 
	'''     Using ReadLock As IDisposable = Locker.GetReadLocker()
	'''       ' Read something
	'''       Dim Size As Integer = ThreadUnsafeList.Count
	'''
	'''       Using WriteLock As IDisposable = Locker.GetWriteLocker()
	'''           ' Write something
	'''           ThreadUnsafeList.Add(5)
	'''       End Using
	''' 
	'''       MessageBox.Show(Me, "Size before: " - Size - ". Size now: " - ThreadUnsafeList.Count)
	''' 
	'''       ' ThreadSafeListView uses the IDisposable Object exclusively for using ReadLocks when it
	'''       '   is being enumerated over via For Each Loops.
	'''       ' It also has the ability to detect when it is being written to within the For Each loop,
	'''       '   and cache those changes until it is unlocked from reading/exits the For Each loop,
	'''       '   using the OnUnlocked events from this class.
	'''     End Using
	'''     </pre>
	''' </remarks>
	<CLSCompliant(True)> _
	Public Class ReadWriteLocker2
		Implements IReadWriteLocker

		#Region "Global Variables"
			Private Shared _AllEntered    As New IdBasedReferenceCounter()
			Private Shared _AllDeadLocked As New IdBasedReferenceCounter()

			' NOTE:  This value controls how long read-locks cycle, not how long until thread safety is ignored.
			'          Recommended not set this to -1/lock indefinatly (instead set LockTimoutRetry = 0)
			'
			' 120,000 ms = 2 min * 60 sec/min * 1000 ms/sec = 2 minutes
			'
			' Currently set to 6 seconds.
			Private Const LockTimeoutMs    As Integer = 6000
			Private Const NoThreadId       As Integer = -1
			Private Const SpinLockCount    As Integer = 92

			Private Shared _GlobalWriteSyncRoot As Integer = 0
			Private Shared _GlobalReadSyncRoot  As Integer = 0
			Private Shared _GlobalUpgradeRoot   As Integer = 0
			Private Shared _GlobalPauseReading  As Integer = 0

			Private Shared _SuperUnlocked   As Integer = NoThreadId
			Private Shared _SuperRunCount   As Integer
			Private Shared _PriorityThreads As New IdBasedReferenceCounter()

			Public Shared Property UseThisThreadAsPriorityThread As Boolean
				Get
					Return _PriorityThreads(Thread.CurrentThread.ManagedThreadId) <> 0
				End Get
				Set
					_PriorityThreads.Increment(Thread.CurrentThread.ManagedThreadId)
				End Set
			End Property
		#End Region

		#Region "Enumerations"
			Public Enum Behavior
				NoDeadLocks
				ThrowOnDeadLocks
				AllowDeadLocks
			End Enum
		#End Region

		#Region "Members"
			Private _ReadLockObject        As New LockObject(Me, LockType.Read)
			Private _WriteLockObject       As New LockObject(Me, LockType.Write)
			Private _TryReadLockObject     As New LockObject(Me, LockType.TryRead)
			Private _TryWriteLockObject    As New LockObject(Me, LockType.TryWrite)

			Private _Behavior              As Behavior
			Private _IsThreadSafe          As Boolean
			Private _CacheIsThreadSafe     As Nullable(Of Boolean)

			Private _WriteThreadId         As Integer = NoThreadId
			Private _ReadingThreadIds      As New IdBasedReferenceCounter()
			'Private _UnbiasLocking         As New List(Of Integer)()

			Private _ReadLockCount         As Integer
			Private _WriteLockCount        As Integer

			Private _IsDisposed            As Boolean = False

			Public Event LockedForReading() _
				Implements ISimpleReadWriteLockerEventTracker.LockedForReading
			Public Event UnlockedForReading() _
				Implements ISimpleReadWriteLockerEventTracker.UnlockedForReading

			Public Event LockedForWriting() _
				Implements ISimpleReadWriteLockerEventTracker.LockedForWriting
			Public Event UnlockedForWriting() _
				Implements ISimpleReadWriteLockerEventTracker.UnlockedForWriting
		#End Region

		#Region "Constructor"
			'Public Sub New(Optional __isThreadSafe As Boolean = True)
			'	IsThreadSafe = __isThreadSafe
			'	_Behavior    = Behavior.ThrowOnDeadLocks
			'End Sub

			Public Sub New(__behavior As Behavior, Optional __isThreadSafe As Boolean = True)
				_IsThreadSafe = __isThreadSafe
				_Behavior     = __behavior
			End Sub
		#End Region

		#Region "Properties"
			#Region "IsThreadSafe"
				Public ReadOnly Property IsThreadSafe As Boolean _
					Implements ISimpleReadWriteLocker.IsThreadSafe

					Get
						Return Not _IsDisposed AndAlso _IsThreadSafe
					End Get
				End Property
			#End Region

			#Region "Locking Count"
				Public ReadOnly Property LockCount As Integer
					Get
						Return _ReadLockCount + _WriteLockCount
					End Get
				End Property

				Public ReadOnly Property ReadLockCount As Integer _
					Implements ISimpleReadWriteLockerEventTracker.ReadLockCount

					Get
						Return _ReadLockCount
					End Get
				End Property

				Public ReadOnly Property WriteLockCount As Integer _
					Implements ISimpleReadWriteLockerEventTracker.WriteLockCount

					Get
						Return _WriteLockCount
					End Get
				End Property
			#End Region

			#Region "IsSuperThreadRunning"
				Public ReadOnly Property IsSuperThreadRunning As Boolean
					Get
						Dim VolatileSuperUnlocked As Integer
						VolatileSuperUnlocked = _SuperUnlocked
						Thread.MemoryBarrier()

						Return VolatileSuperUnlocked <> -1
					End Get
				End Property
			#End Region

			#Region "IsReading/IsWriting/IsLocked"
				Public ReadOnly Property IsReading As Boolean _
					Implements ISimpleReadWriteLocker.IsReading

					Get
						Return _ReadLockCount > 0
					End Get
				End Property

				Public ReadOnly Property IsWriting As Boolean _
					Implements ISimpleReadWriteLocker.IsWriting

					Get
						Return _WriteLockCount > 0
					End Get
				End Property

				Public ReadOnly Property IsLocking As Boolean
					Get
						Return _ReadLockCount > 0 OrElse _WriteLockCount > 0
					End Get
				End Property
			#End Region
		#End Region

		#Region "Methods"
			#Region "Threading"
				#Region "IsCurrentThreadLockedFor[Reading/Writing]"
					Public Function IsCurrentThreadLockedForReading() As Boolean _
						Implements IReadWriteLocker.IsCurrentThreadLockedForReading

						Return True

						'SyncLock _SyncRoot
						'	If _SuperThreadId <> NoThreadId Then
						'		Return _SuperThreadId <> Thread.CurrentThread.ManagedThreadId
						'	End If

						'	SyncLock _ReadingThreadIds
						'		Return _ReadingThreadIds.ContainsKey(Thread.CurrentThread.ManagedThreadId)
						'	End SyncLock
						'End SyncLock
					End Function

					Public Function IsCurrentThreadLockedForWriting() As Boolean _
						Implements IReadWriteLocker.IsCurrentThreadLockedForWriting

						Return True

						'SyncLock _SyncRoot
						'	If _SuperThreadId <> NoThreadId Then
						'		Return _SuperThreadId <> Thread.CurrentThread.ManagedThreadId
						'	End If

						'	Return _WriteThreadId = Thread.CurrentThread.ManagedThreadId
						'End SyncLock
					End Function
				#End Region

				#Region "Begin/End locking, raising appropriate locking event"
					Public Sub LockForReading() _
						Implements IComplexReadWriteLocker.LockForReading

						' Before actually locking, we increment this to show this is locked for reading.
						Interlocked.Increment(_ReadLockCount)
						AddReadLock(False)

						OnLockedForReading()
					End Sub

					Public Sub UnlockForReading() _
						Implements IComplexReadWriteLocker.UnlockForReading

						RemoveReadLock()

						' After we are finished locking, this gets decremented
						'   to show read locking is finished.
						Interlocked.Decrement(_ReadLockCount)

						OnUnlockedForReading()
					End Sub					

					Public Sub TryLockForReading() _
						Implements IComplexReadWriteLocker.TryLockForReading

						' Before actually locking, we increment this to show this is locked for reading.
						Interlocked.Increment(_ReadLockCount)
						AddReadLock(True)

						OnLockedForReading()
					End Sub

					Public Sub TryUnlockForReading() _
						Implements IComplexReadWriteLocker.TryUnlockForReading

						UnlockForReading()
					End Sub

					Public Sub LockForWriting() _
						Implements IComplexReadWriteLocker.LockForWriting

						' Before actually locking, we increment this to show this is locked for writing.
						Interlocked.Increment(_WriteLockCount)

						AddWriteLock(False)
						OnLockedForWriting()
					End Sub

					Public Sub UnlockForWriting() _
						Implements IComplexReadWriteLocker.UnlockForWriting

						RemoveWriteLock()

						' After we are finished locking, this gets decremented
						'   to show write locking is finished.
						Interlocked.Decrement(_WriteLockCount)

						OnUnlockedForWriting()
					End Sub

					Public Sub TryLockForWriting() _
						Implements IComplexReadWriteLocker.TryLockForWriting

						' Before actually locking, we increment this to show this is locked for writing.
						Interlocked.Increment(_WriteLockCount)
						AddWriteLock(True)

						OnLockedForWriting()
					End Sub

					Public Sub TryUnlockForWriting() _
						Implements IComplexReadWriteLocker.TryUnlockForWriting

						UnlockForWriting()
						OnUnlockedForWriting()
					End Sub

					Public Sub LockForReadWriting()
						' Before actually locking, we increment this to show this is locked for writing.
						Interlocked.Increment(_WriteLockCount)

						AddWriteLock(False)
						OnLockedForReadWriting()
					End Sub

					Public Sub UnlockForReadWriting()
						RemoveWriteLock()

						' After we are finished locking, this gets decremented
						'   to show write locking is finished.
						Interlocked.Decrement(_WriteLockCount)

						OnUnlockedForReadWriting()
					End Sub

					Public Sub TryLockForReadWriting()
						' Before actually locking, we increment this to show this is locked for writing.
						Interlocked.Increment(_WriteLockCount)
						AddWriteLock(True)

						OnLockedForReading()
						OnLockedForWriting()
					End Sub

					Public Sub TryUnlockForReadWriting()
						UnlockForWriting()

						OnUnlockedForReading()
						OnUnlockedForWriting()
					End Sub
				#End Region

				#Region "Locking and Unlocking Conditions"
					Private Const NoDeadLockFound        As Integer = 0
					Private Const DeadLockFoundAndBlock  As Integer = 1
					Private Const DeadLockFoundDontBlock As Integer = 2

					'' For speed purposes, we inline this into NeedsLockedForWriting().
					'
					'Private Function CheckForDeadLockAndSetupFix(currentThreadId As Integer) As Integer
					'	If _Behavior = Behavior.NoDeadLocks Then
					'		If Thread.VolatileRead(_SuperRunCount) = 0 Then
					'			If _AllEntered.Count > 1 AndAlso _AllEntered.Count = _AllDeadLocked.Count Then
					'				Dim PriorityThreadFound As Integer = NoThreadId

					'				For Each PriorityThread As IdBasedReferenceCounter.KeyValue In _PriorityThreads
					'					If _AllEntered(PriorityThread.Key) = 0 Then
					'						PriorityThreadFound = PriorityThread.Key

					'						Exit For
					'					End If
					'				Next

					'				If PriorityThreadFound <> -1 Then
					'					Thread.VolatileWrite(_SuperUnlocked, PriorityThreadFound)
					'				Else
					'					Thread.VolatileWrite(_SuperUnlocked, currentThreadId)
					'				End If

					'				Thread.VolatileWrite(_SuperRunCount, 1)

					'				If Thread.VolatileRead(_SuperUnlocked) <> currentThreadId Then
					'					Return DeadLockFoundAndBlock
					'				End If

					'				Return DeadLockFoundDontBlock
					'			Else
					'				Thread.VolatileWrite(_SuperUnlocked, NoThreadId)
					'			End If
					'		Else If Thread.VolatileRead(_SuperUnlocked) <> NoThreadId Then
					'			If Thread.VolatileRead(_SuperUnlocked) = currentThreadId Then
					'				Return DeadLockFoundDontBlock
					'			End If

					'			Return DeadLockFoundAndBlock
					'		End If

					'		Return NoDeadLockFound
					'	Else If _Behavior = Behavior.ThrowOnDeadLocks Then
					'		If Thread.VolatileRead(_SuperRunCount) = NoDeadLockFound Then

					'			If _AllEntered.Count > 1 AndAlso _
					'				_AllEntered.Count = _AllDeadLocked.Count Then

					'				Throw New SynchronizationLockException("Hard lock has occurred for Read Locking.")
					'			End If
					'		End If

					'		Return NoDeadLockFound
					'	Else
					'		' Returns no hard lock has occurred, since we aren't checking.
					'		Return NoDeadLockFound
					'	End If
					'End Function

					Private Function NeedsLockedForReading(currentThreadId As Integer) As Boolean
						Dim VolatileWriteThreadId As Integer
						VolatileWriteThreadId = _WriteThreadId
						Thread.MemoryBarrier()

						Return VolatileWriteThreadId <> NoThreadId AndAlso _
						       VolatileWriteThreadId <> currentThreadId
					End Function

					Private Function NeedsLockedForWriting(currentThreadId As Integer) As Boolean
						Dim VolatileSuper As Integer

						If _Behavior = Behavior.NoDeadLocks Then
							VolatileSuper = _SuperRunCount
							Thread.MemoryBarrier()

							If VolatileSuper = 0 Then
								Dim DeadlockFound As Boolean = _AllEntered.Count > 1 AndAlso (_AllEntered.Count = _AllDeadLocked.Count)
							
								If DeadlockFound Then
									Dim PriorityThreadFound As Integer = NoThreadId

									If _PriorityThreads.Count > 0 Then
										For Each PriorityThread As IdBasedReferenceCounter.KeyValue In _PriorityThreads
											If _AllEntered(PriorityThread.Key) = 0 Then
												PriorityThreadFound = PriorityThread.Key

												Exit For
											End If
										Next
									End If

									If PriorityThreadFound <> -1 Then
										Thread.MemoryBarrier()
										_SuperUnlocked = PriorityThreadFound
									Else
										Thread.MemoryBarrier()
										_SuperUnlocked = currentThreadId
									End If

									Thread.MemoryBarrier()
									_SuperRunCount = 1

									VolatileSuper = _SuperUnlocked
									Thread.MemoryBarrier()

									If VolatileSuper <> currentThreadId Then
										'Return DeadLockFoundAndBlock
										Return False
									End If

									'Return DeadLockFoundDontBlock
									Return True
								Else
									VolatileSuper = _SuperUnlocked
									Thread.MemoryBarrier()

									If VolatileSuper <> NoThreadId Then
										Thread.MemoryBarrier()
										_SuperUnlocked = NoThreadId
									End If
								End If
							Else
								VolatileSuper = _SuperUnlocked
								Thread.MemoryBarrier()

								If VolatileSuper <> NoThreadId Then
									Return VolatileSuper = currentThreadId

									'If VolatileSuper = currentThreadId Then
									'	'Return DeadLockFoundDontBlock
									'	Return True
									'End If

									''Return DeadLockFoundAndBlock
									'Return False
								End If
							End If

							'Return NoDeadLockFound
							'' Continue and run code below.
						Else If _Behavior = Behavior.ThrowOnDeadLocks Then
							VolatileSuper = _SuperRunCount
							Thread.MemoryBarrier()

							If VolatileSuper = NoDeadLockFound Then
								'Dim DeadlockFound As Boolean = (_AllEntered.Count > 1) AndAlso (_AllEntered.Count = _AllDeadLocked.Count)
								'If DeadlockFound Then...End If

								If _AllEntered.Count > 1 AndAlso _AllEntered.Count = _AllDeadLocked.Count Then
									Throw New SynchronizationLockException("Hard lock has occurred for Read Locking.")
								End If
							End If

							'Return NoDeadLockFound
							'' Continue and run code below.
						'Else
						'	' Returns no hard lock has occurred, since we aren't checking.
						'	Return NoDeadLockFound
						'' Nothing to do for Else, since we need to "Continue and run code below."
						End If

						VolatileSuper = _WriteThreadId
						Thread.MemoryBarrier()

						'Dim WritingAllowed As Boolean =     _
						'	VolatileSuper = NoThreadId OrElse _
						'	VolatileSuper = currentThreadId

						'Dim ReadingAllowed As Boolean =        _
						'	_ReadingThreadIds.Count = 0   OrElse _
						'	(_ReadingThreadIds.Count = 1 AndAlso _
						'	 _ReadingThreadIds(currentThreadId) <> 0)

						Dim Allowed As Boolean =            _
							VolatileSuper = NoThreadId OrElse _
							VolatileSuper = currentThreadId

						Allowed = Allowed AndAlso               _
							(_ReadingThreadIds.Count = 0   OrElse _
							 (_ReadingThreadIds.Count = 1 AndAlso _
							  _ReadingThreadIds(currentThreadId) <> 0))

						Return Not Allowed
					End Function

					' Inlined for speed purposes.  Same as NeedsLockedForWriting with Behavior = NoDeadLocks.
					Private Function NeedsLockedForWritingNoDeadLocks(currentThreadId As Integer) As Boolean
						Dim VolatileSuper As Integer
						VolatileSuper = _SuperRunCount
						Thread.MemoryBarrier()

						If VolatileSuper = 0 Then
							Dim DeadlockFound As Boolean = _AllEntered.Count > 1 AndAlso (_AllEntered.Count = _AllDeadLocked.Count)
						
							If DeadlockFound Then
								Dim PriorityThreadFound As Integer = NoThreadId

								If _PriorityThreads.Count > 0 Then
									For Each PriorityThread As IdBasedReferenceCounter.KeyValue In _PriorityThreads
										If _AllEntered(PriorityThread.Key) = 0 Then
											PriorityThreadFound = PriorityThread.Key

											Exit For
										End If
									Next
								End If

								If PriorityThreadFound <> -1 Then
									Thread.MemoryBarrier()
									_SuperUnlocked = PriorityThreadFound
								Else
									Thread.MemoryBarrier()
									_SuperUnlocked = currentThreadId
								End If

								Thread.MemoryBarrier()
								_SuperRunCount = 1

								VolatileSuper = _SuperUnlocked
								Thread.MemoryBarrier()

								If VolatileSuper <> currentThreadId Then
									'Return DeadLockFoundAndBlock
									Return False
								End If

								'Return DeadLockFoundDontBlock
								Return True
							Else
								VolatileSuper = _SuperUnlocked
								Thread.MemoryBarrier()

								If VolatileSuper <> NoThreadId Then
									Thread.MemoryBarrier()
									_SuperUnlocked = NoThreadId
								End If
							End If
						Else
							VolatileSuper = _SuperUnlocked
							Thread.MemoryBarrier()

							If VolatileSuper <> NoThreadId Then
								Return VolatileSuper = currentThreadId

								'If VolatileSuper = currentThreadId Then
								'	'Return DeadLockFoundDontBlock
								'	Return True
								'End If

								''Return DeadLockFoundAndBlock
								'Return False
							End If
						End If

						VolatileSuper = _WriteThreadId
						Thread.MemoryBarrier()

						'Dim WritingAllowed As Boolean =     _
						'	VolatileSuper = NoThreadId OrElse _
						'	VolatileSuper = currentThreadId

						'Dim ReadingAllowed As Boolean =        _
						'	_ReadingThreadIds.Count = 0   OrElse _
						'	(_ReadingThreadIds.Count = 1 AndAlso _
						'	 _ReadingThreadIds(currentThreadId) <> 0)

						Dim Allowed As Boolean =            _
							VolatileSuper = NoThreadId OrElse _
							VolatileSuper = currentThreadId

						Allowed = Allowed AndAlso               _
							(_ReadingThreadIds.Count = 0   OrElse _
							 (_ReadingThreadIds.Count = 1 AndAlso _
							  _ReadingThreadIds(currentThreadId) <> 0))

						Return Not Allowed
					End Function

					' Inlined for speed purposes.  Same as NeedsLockedForWriting with Behavior = ThrowOnDeadLocks.
					Private Function NeedsLockedForWritingThrowOnDeadLock(currentThreadId As Integer) As Boolean
						Dim VolatileSuper As Integer
						VolatileSuper = _SuperRunCount
						Thread.MemoryBarrier()

						If VolatileSuper = NoDeadLockFound Then
							If _AllEntered.Count > 1 AndAlso _
								_AllEntered.Count = _AllDeadLocked.Count Then

								Throw New SynchronizationLockException("Hard lock has occurred for Read Locking.")
							End If
						End If

						VolatileSuper = _WriteThreadId
						Thread.MemoryBarrier()

						'Dim WritingAllowed As Boolean =     _
						'	VolatileSuper = NoThreadId OrElse _
						'	VolatileSuper = currentThreadId

						'Dim ReadingAllowed As Boolean =        _
						'	_ReadingThreadIds.Count = 0   OrElse _
						'	(_ReadingThreadIds.Count = 1 AndAlso _
						'	 _ReadingThreadIds(currentThreadId) <> 0)

						Dim Allowed As Boolean =            _
							VolatileSuper = NoThreadId OrElse _
							VolatileSuper = currentThreadId

						Allowed = Allowed AndAlso               _
							(_ReadingThreadIds.Count = 0   OrElse _
							 (_ReadingThreadIds.Count = 1 AndAlso _
							  _ReadingThreadIds(currentThreadId) <> 0))

						Return Not Allowed
					End Function

					' Inlined for speed purposes.  Same as NeedsLockedForWriting with Behavior = AllowDeadLocks.
					Private Function NeedsLockedForWritingAllowDeadLocks(currentThreadId As Integer) As Boolean
						Dim VolatileSuper As Integer
						VolatileSuper = _WriteThreadId
						Thread.MemoryBarrier()

						'Dim WritingAllowed As Boolean =     _
						'	VolatileSuper = NoThreadId OrElse _
						'	VolatileSuper = currentThreadId

						'Dim ReadingAllowed As Boolean =        _
						'	_ReadingThreadIds.Count = 0   OrElse _
						'	(_ReadingThreadIds.Count = 1 AndAlso _
						'	 _ReadingThreadIds(currentThreadId) <> 0)

						Dim Allowed As Boolean =            _
							VolatileSuper = NoThreadId OrElse _
							VolatileSuper = currentThreadId

						Allowed = Allowed AndAlso               _
							(_ReadingThreadIds.Count = 0   OrElse _
							 (_ReadingThreadIds.Count = 1 AndAlso _
							  _ReadingThreadIds(currentThreadId) <> 0))

						Return Not Allowed
					End Function
				#End Region

				#Region "External Read/Write Locking"
					''' <summary>
					'''   Gets an object which locks this collection so reading
					'''     can happen multiple times.
					''' </summary>
					''' <remarks>
					'''   If this thread currently has this locked for writing,
					'''     it uses the writelock instead of the readlock.
					'''
					'''   WARNING: If explicitly cast to Object (instead of being IDisposable)
					'''              in Using block, Dispose method will never get called.
					'''              So be careful if Option Explicit is not turned on.
					'''   Example:
					''' 
					'''     ' This never calls IDisposable!
					'''     Using Locker As Object = List.GetReadLock()
					'''       ' Do reading.  Dispose Method will never be called...
					'''     End Using
					''' 
					'''     ' Correct
					'''     Using Locker As List.GetReadLock()
					'''       ' Do reading.
					'''     End Using
					''' </remarks>
					Public Function GetReadLock() As IDisposable     _
						Implements ISimpleReadWriteLocker.GetReadLock

						Return _ReadLockObject.GetLock()
					End Function

					''' <summary>
					'''   Gets an object which locks this collection so writing
					'''     can occur.
					''' </summary>
					''' <remarks>
					'''   If this thread currently has this locked for writing,
					'''     it uses the writelock instead of the readlock.
					'''
					'''   WARNING: If explicitly cast to Object (instead of being IDisposable)
					'''              in Using block, Dispose method will never get called.
					'''              So be careful if Option Explicit is not turned on.
					'''   Example:
					''' 
					'''     ' This never calls IDisposable!
					'''     Using Locker As Object = List.GetWriteLock()
					'''       ' Do Writing.  Dispose Method will never be called...
					'''     End Using
					''' 
					'''     ' Correct
					'''     Using Locker As List.GetWriteLock()
					'''       ' Do Writing.
					'''     End Using
					'''
					'''   Also note that the For Each statement uses a ReaderLock,
					'''     but it is valid to write while reading, so long as no
					'''     other threads are reading as well.
					''' </remarks>
					Public Function GetWriteLock() As IDisposable     _
						Implements ISimpleReadWriteLocker.GetWriteLock, _
						           IReadWriteLocker.GetSyncLock,        _
						           IReadWriteLocker.GetLock

						Return _WriteLockObject.GetLock()
					End Function

					Public Function TryGetReadLock() As IDisposable _
						Implements ISimpleReadWriteLocker.TryGetReadLock

						Return _TryReadLockObject.GetLock()
					End Function

					Public Function TryGetWriteLock() As IDisposable _
						Implements ISimpleReadWriteLocker.TryGetWriteLock

						Return _TryWriteLockObject.GetLock()
					End Function

					''' <summary>
					'''   Alias for GetWriteLock().  This is meant to be used in
					'''     Visual Basic code to replace SyncLock object/End SyncLock.
					''' </summary>
					Public Function GetSyncLock() As IDisposable
						Return GetWriteLock()
					End Function

					''' <summary>
					'''   Alias for getWriteLock().  This is meant to be used in
					'''     C# code to replace lock(object) {}.
					''' </summary>
					''' <returns></returns>
					''' <remarks></remarks>
					Public Function GetLock() As IDisposable
						Return GetWriteLock()
					End Function
				#End Region

				#Region "Locking and Unlocking"
					Private Sub AddReadLock(tryAddReadLock As Boolean)
						Dim CurrentThreadId As Integer = Thread.CurrentThread.ManagedThreadId

						If _Behavior = Behavior.NoDeadLocks OrElse _Behavior = Behavior.ThrowOnDeadLocks Then
							_AllEntered.Increment(CurrentThreadId)

							Dim VolatileSuperUnlocked As Integer
							VolatileSuperUnlocked = _SuperUnlocked
							Thread.MemoryBarrier()

							If VolatileSuperUnlocked = CurrentThreadId Then
								Interlocked.Increment(_SuperRunCount)
							End If
						End If

						If NeedsLockedForReading(CurrentThreadId) Then
							If _Behavior = Behavior.NoDeadLocks OrElse _Behavior = Behavior.ThrowOnDeadLocks Then
								_AllDeadLocked.Increment(CurrentThreadId)
							End If

							If Not tryAddReadLock Then
								Dim MultiProcessor As Boolean = Environment.ProcessorCount > 1
								Dim SpinWait       As Integer = 1

								While NeedsLockedForReading(CurrentThreadId)
										If SpinWait < 11 AndAlso MultiProcessor Then
											Thread.SpinWait(20 * SpinWait)
										ElseIf (SpinWait < 16) Then
												Thread.Sleep(0)
										Else
												Thread.Sleep(1)
										End If

										SpinWait += 1
								End While
							End If

							If _Behavior = Behavior.NoDeadLocks OrElse _Behavior = Behavior.ThrowOnDeadLocks Then
								_AllDeadLocked.Decrement(CurrentThreadId)
							End If
						End If

						_ReadingThreadIds.Increment(CurrentThreadId)
					End Sub

					Private Sub RemoveReadLock()
						Dim CurrentThreadId As Integer = Thread.CurrentThread.ManagedThreadId

						_ReadingThreadIds.Decrement(CurrentThreadId)						

						If _Behavior = Behavior.NoDeadLocks OrElse _Behavior = Behavior.ThrowOnDeadLocks Then
							_AllEntered.Decrement(CurrentThreadId)

							Dim VolatileSuperUnlocked As Integer
							VolatileSuperUnlocked = _SuperUnlocked
							Thread.MemoryBarrier()

							If VolatileSuperUnlocked = CurrentThreadId Then
								If Interlocked.Decrement(_SuperRunCount) = 0 Then
									Thread.MemoryBarrier()
									_SuperUnlocked = NoThreadId
								End If
							End If
						End If
					End Sub

					Private Sub AddWriteLock(tryAddWriteLock As Boolean)
						Dim CurrentThreadId   As Integer = Thread.CurrentThread.ManagedThreadId

						If _Behavior = Behavior.NoDeadLocks OrElse _Behavior = Behavior.ThrowOnDeadLocks Then
							_AllEntered.Increment(CurrentThreadId)

							Dim VolatileSuper As Integer
							VolatileSuper = _SuperUnlocked
							Thread.MemoryBarrier()

							If VolatileSuper = CurrentThreadId Then
								Interlocked.Increment(_SuperRunCount)
							End If
						End If

						If NeedsLockedForWriting(CurrentThreadId) Then
							If _Behavior = Behavior.NoDeadLocks OrElse _Behavior = Behavior.ThrowOnDeadLocks Then
								_AllDeadLocked.Increment(CurrentThreadId)
							End If

							If Not tryAddWriteLock Then
								Dim MultiProcessor As Boolean = Environment.ProcessorCount > 1
								Dim SpinWait       As Integer = 1

								' Because extra work is being done, spin locking must
								'   not spin as much in NoDeadLocks and ThrowOnDeadLocks.
								If _Behavior = Behavior.NoDeadLocks Then
									While NeedsLockedForWritingNoDeadLocks(CurrentThreadId)
										If SpinWait < 11 Then 'AndAlso MultiProcessor Then
											Thread.SpinWait(20 * SpinWait)
										ElseIf (SpinWait < 16) Then
												Thread.Sleep(0)
										Else
												Thread.Sleep(1)
										End If

										SpinWait += 1
									End While
								Else If False AndAlso _Behavior = Behavior.AllowDeadLocks Then
									While NeedsLockedForWritingAllowDeadLocks(CurrentThreadId)
										If SpinWait < 11 AndAlso MultiProcessor Then
											Thread.SpinWait(7 * SpinWait)
										ElseIf (SpinWait < 16) Then
												Thread.Sleep(0)
										Else
												Thread.Sleep(1)
										End If

										SpinWait += 1
									End While
								Else
									While NeedsLockedForWritingThrowOnDeadLock(CurrentThreadId)
										If SpinWait < 11 AndAlso MultiProcessor Then
											Thread.SpinWait(12 * SpinWait)
										ElseIf (SpinWait < 16) Then
												Thread.Sleep(0)
										Else
												Thread.Sleep(1)
										End If

										SpinWait += 1
									End While
								End If
							End If

							If _Behavior = Behavior.NoDeadLocks OrElse _Behavior = Behavior.ThrowOnDeadLocks Then
								_AllDeadLocked.Decrement(CurrentThreadId)
							End If
						End If


						Dim VolatileSuperUnlocked As Integer
						VolatileSuperUnlocked = _SuperUnlocked
						Thread.MemoryBarrier()

						If VolatileSuperUnlocked = CurrentThreadId Then
							Thread.MemoryBarrier()
							_WriteThreadId = CurrentThreadId
						End If
					End Sub

					Private Sub RemoveWriteLock()
						Dim CurrentThreadId As Integer = Thread.CurrentThread.ManagedThreadId
						Dim VolatileSuperUnlocked As Integer

						If _Behavior = Behavior.NoDeadLocks OrElse _Behavior = Behavior.ThrowOnDeadLocks Then
							' Decrements the current key.
							_AllEntered.Decrement(CurrentThreadId)

							VolatileSuperUnlocked = _SuperUnlocked
							Thread.MemoryBarrier()

							If VolatileSuperUnlocked <> NoThreadId Then
								If Interlocked.Decrement(_SuperRunCount) = 0 Then
									Interlocked.CompareExchange(_SuperUnlocked, NoThreadId, CurrentThreadId)
								End If
							End If
						End If

						VolatileSuperUnlocked = _SuperUnlocked
						Thread.MemoryBarrier()

						If VolatileSuperUnlocked = 0 Then
							Thread.MemoryBarrier()
							_WriteThreadId = NoThreadId
						End If
					End Sub
				#End Region

				#Region "Locking Events"
					Protected Overridable Sub OnLockedForReading()
						RaiseEvent LockedForReading()
					End Sub

					Protected Overridable Sub OnLockedForWriting()
						RaiseEvent LockedForWriting()
					End Sub

					Protected Overridable Sub OnLockedForReadWriting()
						RaiseEvent LockedForReading()
						RaiseEvent LockedForWriting()
					End Sub

					Protected Overridable Sub OnUnlockedForReading()
						RaiseEvent UnlockedForReading()
					End Sub

					Protected Overridable Sub OnUnlockedForWriting()
						RaiseEvent UnlockedForWriting()
					End Sub

					Protected Overridable Sub OnUnlockedForReadWriting()
						RaiseEvent UnlockedForReading()
						RaiseEvent UnlockedForWriting()
					End Sub
				#End Region
			#End Region

			#Region "IDisposable"
				' IDisposable
				Protected Overridable Sub Dispose(disposing As Boolean)
					If Not _IsDisposed Then
						_IsDisposed = True
					End If
				End Sub

				#Region " IDisposable Support "
					' This code added by Visual Basic to correctly implement the disposable pattern.
					Public Sub Dispose() _
						Implements IDisposable.Dispose

						'' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
						Dispose(True)
						GC.SuppressFinalize(Me)
					End Sub

					' Makes sure that the Global Hard-Lock Tracking has this removed from it.
					Protected Overrides Sub Finalize()
						Dispose(False)
					End Sub
				#End Region
			#End Region
		#End Region
	End Class
#End Region

#Region "ReadWriteLocker"
	<CLSCompliant(True)> _
	Public Interface ISimpleReadWriteLocker2
		''' <summary>
		'''   Gets a disposible object that starts read locking
		'''     for the duration of the objects lifespan, and
		'''     stops read locking once the object gets disposed.
		''' </summary>
		''' <remarks>
		'''   The object being returned doesn't necessarily have to
		'''     be made and garbage collected each time this is called.
		'''   This can be done by having the read-write locker hold a
		'''     reference to the IDisposable Object, start read locking,
		'''     and then let IDispose call to end read locking.
		''' 
		'''   An example on where to use this would be in the getter of a property.
		''' </remarks>
		Function GetReadLock()  As IDisposable

		''' <summary>
		'''   Gets a disposible object that starts write locking
		'''     for the duration of the objects lifespan, and
		'''     stops write locking once the object gets disposed.
		''' </summary>
		''' <remarks>
		'''   The object being returned doesn't necessarily have to
		'''     be made and garbage collected each time this is called.
		'''   This can be done by having the read-write locker hold a
		'''     reference to the IDisposable Object, start read locking,
		'''     and then let IDispose call to end read locking.
		''' 
		'''   An example on where to use this would be the setter of a property.
		''' </remarks>
		Function GetWriteLock() As IDisposable

		''' <summary>
		'''   Gets a disposible object that starts read-write locking
		'''     for the duration of the objects lifespan, and
		'''     stops read-write locking once the object gets disposed.
		''' </summary>
		''' <remarks>
		'''   The object being returned doesn't necessarily have to
		'''     be made and garbage collected each time this is called.
		'''   This can be done by having the read-write locker hold a
		'''     reference to the IDisposable Object, start read locking,
		'''     and then let IDispose call to end read locking.
		''' 
		'''   Read-write locking differs from write locking in that
		'''     IsReading returns true.  It should be used anytime that
		'''     data could be read from and written to at the same time.
		''' 
		'''   An example on where to use this would be method/function that
		'''     both manipulates and return a field/variable.
		'''   <code>
		'''     Using ReadWriteLock As IDisposable = GetReadWriteLock()
		'''       // Perform reading and writing functionality here.
		'''     End Using
		'''   </code>
		''' </remarks>
		Function GetReadWriteLock() As IDisposable
	End Interface

	<CLSCompliant(True)> _
	Public Interface IComplexReadWriteLocker2
		Inherits ISimpleReadWriteLocker2

		''' <summary>
		'''   Starts read locking.  <seealso>GetReadLock</seealso>() is simply a wrapper
		'''     using this functionality.
		''' 
		'''   <see>UnlockForReading</see>() must be called to finish read locking.
		''' </summary>
		''' <remarks>
		'''   More details can be seen by reading <seealso>GetReadLock</seealso>().
		''' </remarks>
		Sub LockForReading()
		''' <summary>
		'''   Ends read locking. <see>LockForReading</see>() must be called
		'''     before calling this.
		'''
		'''   More details can be seen by reading <seealso>GetReadLock</seealso>().
		''' </summary>
		Sub UnlockForReading()

		''' <summary>
		'''   Starts write locking.  <seealso>GetWriteLock</seealso>() is simply a wrapper
		'''     using this functionality.
		''' 
		'''   <see>UnlockForWriting</see>() must be called to finish write locking.
		''' </summary>
		''' <remarks>
		'''   More details can be seen by reading <seealso>GetWriteLock</seealso>().
		''' </remarks>
		Sub LockForWriting()
		''' <summary>
		'''   Ends write locking. <see>LockForWriting</see>() must be called
		'''     before calling this.
		'''
		'''   More details can be seen by reading <seealso>GetWriteLock</seealso>().
		''' </summary>
		Sub UnlockForWriting()

		''' <summary>
		'''   Starts read-write locking.  <seealso>GetReadWriteLock</seealso>() is simply a wrapper
		'''     using this functionality.
		''' 
		'''   <see>UnlockForReadWriting</see>() must be called to finish read-write locking.
		''' </summary>
		''' <remarks>
		'''   More details can be seen by reading <seealso>GetReadWriteLock</seealso>().
		''' </remarks>
		Sub LockForReadWriting()
		''' <summary>
		'''   Ends read-write locking. <see>LockForReadWriting</see>() must be called
		'''     before calling this.
		'''
		'''   More details can be seen by reading <seealso>GetReadWriteLock</seealso>().
		''' </summary>
		Sub UnlockForReadWriting()
	End Interface

	<CLSCompliant(True)> _
	Public Interface IReadWriteLockerEventTracker2
		''' <summary>
		'''   Returns true when reading or read-writing is occurring.  Otherwise, false.
		''' </summary>
		ReadOnly Property IsReading As Boolean
		''' <summary>
		'''   Returns true when writing or read-writing is occurring.  Otherwise, false.
		''' </summary>
		ReadOnly Property IsWriting As Boolean

		''' <summary>
		'''   If it doesn't result in locking, starts reading and returns true.
		'''     Otherwise, this returns false.
		''' 
		'''   You must call <see>TryUnlockForReading</see>([boolean]) using the
		'''     returned value from calling this.
		''' </summary>
		''' <remarks>
		'''   You also shouldn't call <see>IsReading</see> to determine if you can
		'''     lock or not, as it isn't atomic. Between calling IsReading
		'''     and actually locking, it can change unexpectedly--making.
		''' 
		'''   This is useful if you are polling a variable, and you only want to
		'''     read it when it is available for reading.
		''' 
		'''   Unfortunately an IDisposable version isn't useful, as it wouldn't be as
		'''     intuitive to have to check a variable within the returned IDisposable object.
		'''     And the IDisposable object would have to be made and garbage collected each time.
		''' 
		'''   Or instead of polling, you can use this within the methods handling
		'''     <see>LockedForReading</see>, <see>UnlockedForReading</see>,
		'''     <see>LockedForWriting</see>, <see>UnlockedForWriting</see> Events.
		''' 
		'''   Example:
		''' 
		'''   <code>
		'''     Private Sub OnUnlocked() Handles UnlockedForReading, UnlockedForWriting
		'''       Dim Reading As Boolean = False
		''' 
		'''       Try
		'''         Reading = TryLockForReading()
		''' 
		'''         If Reading Then
		'''           ' Perform read locking required functionality.
		'''         End If
		'''       Finally
		'''         ' Only unlocks if it was locked.
		'''         TryUnlockedForReading(Reading)
		'''       End Try
		'''     End Sub
		'''   </code>
		''' </remarks>
		Function TryLockForReading() As Boolean
		''' <summary>
		'''   Ends read locking. <see>LockForReading</see>() must be called
		'''     before calling this.
		'''
		'''   More details can be seen by reading <seealso>GetReadLock</seealso>().
		''' </summary>
		Function TryUnlockForReading() As Boolean

		''' <summary>
		'''   Starts write locking.  <seealso>GetWriteLock</seealso>() is simply a wrapper
		'''     using this functionality.
		''' 
		'''   <see>UnlockForWriting</see>() must be called to finish write locking.
		''' </summary>
		''' <remarks>
		'''   More details can be seen by reading <seealso>GetWriteLock</seealso>().
		''' </remarks>
		Function TryLockForWriting() As Boolean
		''' <summary>
		'''   Ends write locking. <see>LockForWriting</see>() must be called
		'''     before calling this.
		'''
		'''   More details can be seen by reading <seealso>GetWriteLock</seealso>().
		''' </summary>
		Function TryUnlockForWriting() As Boolean

		''' <summary>
		'''   Starts read-write locking.  <seealso>GetReadWriteLock</seealso>() is simply a wrapper
		'''     using this functionality.
		''' 
		'''   <see>UnlockForReadWriting</see>() must be called to finish read-write locking.
		''' </summary>
		''' <remarks>
		'''   More details can be seen by reading <seealso>GetReadWriteLock</seealso>().
		''' </remarks>
		Function TryLockForReadWriting() As Boolean
		''' <summary>
		'''   Ends read-write locking. <see>LockForReadWriting</see>() must be called
		'''     before calling this.
		'''
		'''   More details can be seen by reading <seealso>GetReadWriteLock</seealso>().
		''' </summary>
		Function TryUnlockForReadWriting() As Boolean

		''' <summary>
		'''   Fires an event that reading has started. For thread-safety,
		'''     it won't fire until the read lock stops waiting, if needed,
		'''     and starts read-locking.  As such, any code executed in this
		'''     fired event will be locked for reading.
		''' </summary>
		Event LockedForReading()
		''' <summary>
		'''   Fires an event that reading has finished.  You can then
		'''     use <see>TryLockForReading</see>() or <see>TryLockForWriting</see>()
		'''     to poll for a read or write lock.
		''' </summary>
		Event UnlockedForReading()

		''' <summary>
		'''   Fires an event that writing has started. For thread-safety,
		'''     it won't fire until the read lock stops waiting, if needed,
		'''     and starts read-locking.  As such, any code executed in this
		'''     fired event will be locked for reading.
		''' </summary>
		Event LockedForWriting()
		''' <summary>
		'''   Fires an event that writing has occurred.  You can then
		'''     use <see>TryLockForReading</see>() or <see>TryLockForWriting</see>()
		'''     to poll for a read or write lock.
		''' </summary>
		Event UnlockedForWriting()
	End Interface

	<CLSCompliant(True)> _
	Public Interface IReadWriteLocker2
		Inherits IComplexReadWriteLocker, IReadWriteLockerEventTracker2

		''' <summary>
		'''   Determines if the super thread locking is taking place.
		'''     This is useful if locking occurs within a task, causing
		'''     data corruption if the data consistancy contract is broken.
		''' </summary>
		''' <remarks>
		'''   This allows running of alternative code which either does not
		'''     suffer from this potential corruption, or throwing exceptions
		'''     to determine and correct places where this might cause an issue.
		'''
		'''   The only time this can be true is when this locker is setup to
		'''     perform super thread locking.
		''' </remarks>
		ReadOnly Property IsPreventingDeadlock As Boolean
	End Interface

	''' <summary>
	'''  This class is used by ReadWriteLocker2 to keep track of all
  '''    super-threads.
  '''
	'''  Since there can be only one super threads across each ReadWriteLocker2,
  '''    and there can be multiple ReadWriteLocker2's, this class makes sure
  '''    those individual super-threads do not cause deadlocks.
  '''
  '''  And because super-threads are ideally small, if not, never done, this
  '''    class should have the smallest amount of overhead associated with it.
	''' </summary>
  <CLSCompliant(True)> _
	Friend Class GlobalReadWriteLocker

	End Class

	''' <summary>
	'''   A read-write locker which allows for customization via
	'''     Pocking-Policies.  These Policies allow for various
	'''     handling of deadlocks, and preventing of deadlocks.
	''' 
	'''   It has a lot of provisions for preventing the
	'''     same thread from locking itself by automatically
	'''     handling the ReadLock to WriteLock Upgrade/Downgrade.
	''' </summary>
	''' <remarks>
	'''   Example:
	''' 
	'''   <pre>
	'''     Dim Locker As New ReadWriteLocker()
	'''     Dim ThreadUnsafeList As New List(Of Integer)()
	''' 
	'''     Try
	'''       Locker.LockForReading()
	''' 
	'''       ' Read something
	'''       Dim Size As Integer = ThreadUnsafeList.Count
	''' 
	'''       Try
	'''         Locker.LockForWriting()
	'''           ' Write something
	'''           ThreadUnsafeList.Add(5)
	'''       Finally
	'''         Locker.UnlockForWriting()
	'''       End Try
	''' 
	'''       MessageBox.Show(Me, "Size before: " - Size - ". Size now: " - ThreadUnsafeList.Count)
	'''     Finally
	'''       Locker.UnlockForReading()
	'''     End Try
	'''
	'''     ' Note:  This way makes a new Object each time it is used,
	'''     '        but in most situations, that is neglegable.
	'''     ' Or with using the IDisposable Objects:
	''' 
	'''     Dim Locker As New ReadWriteLocker()
	'''     Dim ThreadUnsafeList As New List(Of Integer)()
	''' 
	'''     Using ReadLock As IDisposable = Locker.GetReadLocker()
	'''       ' Read something
	'''       Dim Size As Integer = ThreadUnsafeList.Count
	'''
	'''       Using WriteLock As IDisposable = Locker.GetWriteLocker()
	'''           ' Write something
	'''           ThreadUnsafeList.Add(5)
	'''       End Using
	''' 
	'''       MessageBox.Show(Me, "Size before: " - Size - ". Size now: " - ThreadUnsafeList.Count)
	''' 
	'''       ' ThreadSafeListView uses the IDisposable Object exclusively for using ReadLocks when it
	'''       '   is being enumerated over via For Each Loops.
	'''       ' It also has the ability to detect when it is being written to within the For Each loop,
	'''       '   and cache those changes until it is unlocked from reading/exits the For Each loop,
	'''       '   using the OnUnlocked events from this class.
	'''     End Using
	'''     </pre>
	''' </remarks>
	<CLSCompliant(True)> _
	Public Class ReadWriteLocker
		Implements IReadWriteLocker

		#Region "Constants"
			Private Const NoThreadId As Integer = -1

			' NOTE:  This value controls how long read-locks cycle, not how long until thread safety is ignored.
			'          Recommended not set this to -1/lock indefinatly (instead set LockTimoutRetry = 0)
			'
			' 120,000 ms = 2 min * 60 sec/min * 1000 ms/sec = 2 minutes
			'
			' Currently set to 6 seconds.
			Private Const LockTimeoutMs As Integer = 6000
			Private Const SpinLockCount As Integer = 92
		#End Region

		#Region "Thread Specific Variables"
			' Tracks per-thread when _NumberOfThreadsEnteredReading or _NumberOfThreadsEnteredWriting should be
      '   incremented or decremented.  When below goes from 0 to 1, respectfully one of the two mentioned
      '   variables gets incremented.  And when it goes from 1 to 0, one of the two mentioned gets decremented.
			<ThreadStatic> _
			Private Shared _ThisThreadLockedForReading As Dictionary(Of Integer, Integer)
			<ThreadStatic> _
			Private Shared _ThisThreadLockedForWriting As Dictionary(Of Integer, Integer)

			<ThreadStatic> _
			Private Shared _ThisThreadBeganReading As Dictionary(Of Integer, Integer)
			<ThreadStatic> _
			Private Shared _ThisThreadBeganWriting As Dictionary(Of Integer, Integer)

			<ThreadStatic> _
			Private Shared _ThisThreadReading As Dictionary(Of Integer, Integer)
			<ThreadStatic> _
			Private Shared _ThisThreadWriting As Dictionary(Of Integer, Integer)

			<ThreadStatic> _
			Private Shared _ThisThreadSuperThread As Dictionary(Of Integer, Integer)
		#End Region ' These are all thread-safe, as each thread has a different instance of this static field.

		#Region "Global Variables"
		#End Region

		#Region "Enumerations"
			Public Enum Behavior
				NoThreadSafety   = &H0
				NoDeadLocks      = &H1
				ThrowOnDeadLocks = &H2
				AllowDeadLocks   = &H3
			End Enum
		#End Region

		#Region "Members"
			Private _ReadLockObject     As New LockObject(Me, LockType.Read)
			Private _WriteLockObject    As New LockObject(Me, LockType.Write)
			Private _TryReadLockObject  As New LockObject(Me, LockType.TryRead)
			Private _TryWriteLockObject As New LockObject(Me, LockType.TryWrite)

			Private _Behavior As Behavior

			' This only tracks the number of threads that are locked within begin reading or begin writing methods.
			Private _NumberOfThreadsEnteredReading As Integer
			Private _NumberOfThreadsEnteredWriting As Integer
			Private _NumberOfThreadsEnteredLocking As Integer

			' This tracks the number of threads that have entered read or write locking.
			'   It gets incrememted when the above does, but does not get decremented until after
      '   the end reading or end writing method is called.
			Private _NumberOfThreadsBeganReading As Integer
			Private _NumberOfThreadsBeganWriting As Integer
			Private _NumberOfThreadsBeganLocking As Integer

			Private _NumberOfThreadsReading As Integer
			Private _NumberOfThreadsWriting As Integer
			Private _NumberOfThreadsLocking As Integer

			' If all threads get locked up, then regular read-writing pauses and a "preemptive"
      '   read/write super-thread is selected to run until the deadlock no longer exists, or
      '   it finishes and another super-thread is selected to take its place.
			Private _NumberOfSuperThreads As Integer

			Private _IsDisposed As Boolean = False
		#End Region

		Public ReadOnly Property AnotherThreadWriting As Boolean
			Get
				Dim ThreadWritingCount As Integer = 0

				If _ThisThreadSuperThread IsNot Nothing Then
					_ThisThreadSuperThread.TryGetValue(GetHashCode(), ThreadWritingCount)
				End If

				' If the super-thread is enabled, then override normal functionality.
				If ThreadWritingCount > 0 Then
					Return False
				Else If Thread.VolatileRead(_NumberOfSuperThreads) > 0 Then
					Return True
				End If

				If _ThisThreadLockedForWriting IsNot Nothing Then
					_ThisThreadLockedForWriting.TryGetValue(GetHashCode(), ThreadWritingCount)
				End If

				Return ThreadWritingCount = 0 AndAlso Thread.VolatileRead(_NumberOfThreadsWriting) > 0
			End Get
		End Property 

		Public ReadOnly Property OtherThreadsReading As Boolean
			Get
				Dim ThisThreadIsReading As Integer = 0

				If _ThisThreadSuperThread IsNot Nothing Then
					_ThisThreadSuperThread.TryGetValue(GetHashCode(), ThisThreadIsReading)
				End If

				' If the super-thread is enabled, then override normal functionality.
				If ThisThreadIsReading > 0 Then
					Return False
				Else If Thread.VolatileRead(_NumberOfSuperThreads) > 0 Then
					Return True
				End If

				If _ThisThreadLockedForReading IsNot Nothing Then
					_ThisThreadLockedForReading.TryGetValue(GetHashCode(), ThisThreadIsReading)

					If ThisThreadIsReading > 1 Then
						ThisThreadIsReading = 1
					End If
				End If

				Return ThisThreadIsReading < Thread.VolatileRead(_NumberOfThreadsReading) 
			End Get
		End Property

		Public ReadOnly Property SuperThreadReading As Boolean
			Get
				Dim ThisThreadIsReading As Integer = 0

				If _ThisThreadSuperThread IsNot Nothing Then
					_ThisThreadSuperThread.TryGetValue(GetHashCode(), ThisThreadIsReading)
				End If

				' If the super-thread is enabled, then override normal functionality.
				If ThisThreadIsReading > 0 Then
					Return False
				Else If Thread.VolatileRead(_NumberOfSuperThreads) > 0 Then
					Return True
				End If

				Return False
			End Get
		End Property

		Private Sub IncrementEnteredReadLockingCount()
			If _ThisThreadLockedForReading Is Nothing Then
				_ThisThreadLockedForReading = New Dictionary(Of Integer, Integer)()
			End If

			Dim LockedForReadCount As Integer = 0
			Dim HashCode           As Integer = GetHashCode()

			If _ThisThreadLockedForReading.TryGetValue(HashCode, LockedForReadCount) Then
				_ThisThreadLockedForReading(HashCode) = LockedForReadCount + 1
			Else
				Interlocked.Increment(_NumberOfThreadsEnteredReading)
				Interlocked.Increment(_NumberOfThreadsEnteredLocking)
				_ThisThreadLockedForReading = New Dictionary(Of Integer, Integer)()
				_ThisThreadLockedForReading.Add(HashCode, 1)
			End If
		End Sub

		Private Sub DecrementEnteredReadLockingCount()
			Dim HashCode           As Integer = GetHashCode()
			Dim LockedForReadCount As Integer = _ThisThreadLockedForReading(HashCode)

			If LockedForReadCount = 1 Then
				Interlocked.Decrement(_NumberOfThreadsEnteredLocking)
				Interlocked.Decrement(_NumberOfThreadsEnteredReading)
				_ThisThreadLockedForReading.Remove(HashCode)
			Else
				_ThisThreadLockedForReading(HashCode) = LockedForReadCount - 1
			End If
		End Sub

		Private Sub IncrementEnteredWriteLockingCount()
			If _ThisThreadLockedForWriting Is Nothing Then
				_ThisThreadLockedForWriting = New Dictionary(Of Integer, Integer)()
			End If

			Dim LockedForWriteCount As Integer = 0
			Dim HashCode           As Integer = GetHashCode()

			If _ThisThreadLockedForWriting.TryGetValue(HashCode, LockedForWriteCount) Then
				_ThisThreadLockedForWriting(HashCode) = LockedForWriteCount + 1
			Else
				Interlocked.Increment(_NumberOfThreadsEnteredWriting)
				Interlocked.Increment(_NumberOfThreadsEnteredLocking)

				_ThisThreadLockedForWriting = New Dictionary(Of Integer, Integer)()
				_ThisThreadLockedForWriting.Add(HashCode, 1)
			End If
		End Sub

		Private Sub DecrementEnteredWriteLockingCount()
			Dim HashCode           As Integer = GetHashCode()
			Dim LockedForWriteCount As Integer = _ThisThreadLockedForWriting(HashCode)

			If LockedForWriteCount = 1 Then
				Interlocked.Decrement(_NumberOfThreadsEnteredLocking)
				Interlocked.Decrement(_NumberOfThreadsEnteredWriting)

				_ThisThreadLockedForWriting.Remove(HashCode)
			Else
				_ThisThreadLockedForWriting(HashCode) = LockedForWriteCount - 1
			End If
		End Sub

		Private Sub IncrementBeganReadLockingCount()
			If _ThisThreadBeganReading Is Nothing Then
				_ThisThreadBeganReading = New Dictionary(Of Integer, Integer)()
			End If

			Dim ReadCount As Integer = 0
			Dim HashCode  As Integer = GetHashCode()

			If _ThisThreadBeganReading.TryGetValue(HashCode, ReadCount) Then
				_ThisThreadBeganReading(HashCode) = ReadCount + 1
			Else
				Interlocked.Increment(_NumberOfThreadsBeganReading)
				Interlocked.Increment(_NumberOfThreadsBeganLocking)

				_ThisThreadBeganReading = New Dictionary(Of Integer, Integer)()
				_ThisThreadBeganReading.Add(HashCode, 1)
			End If
		End Sub

		Private Sub DecrementBeganReadLockingCount()
			Dim HashCode  As Integer = GetHashCode()
			Dim ReadCount As Integer = _ThisThreadBeganReading(HashCode)

			If ReadCount = 1 Then
				Interlocked.Decrement(_NumberOfThreadsBeganLocking)
				Interlocked.Decrement(_NumberOfThreadsBeganReading)

				_ThisThreadBeganReading.Remove(HashCode)
			Else
				_ThisThreadBeganReading(HashCode) = ReadCount - 1
			End If
		End Sub

		Private Sub IncrementBeganWriteLockingCount()
			If _ThisThreadBeganWriting Is Nothing Then
				_ThisThreadBeganWriting = New Dictionary(Of Integer, Integer)()
			End If

			Dim WriteCount As Integer = 0
			Dim HashCode   As Integer = GetHashCode()

			If _ThisThreadBeganWriting.TryGetValue(HashCode, WriteCount) Then
				_ThisThreadBeganWriting(HashCode) = WriteCount + 1
			Else
				Interlocked.Increment(_NumberOfThreadsBeganWriting)
				Interlocked.Increment(_NumberOfThreadsBeganLocking)

				_ThisThreadBeganWriting = New Dictionary(Of Integer, Integer)()
				_ThisThreadBeganWriting.Add(HashCode, 1)
			End If
		End Sub

		Private Sub DecrementBeganWriteLockingCount()
			Dim HashCode   As Integer = GetHashCode()
			Dim WriteCount As Integer = _ThisThreadBeganWriting(HashCode)

			If WriteCount = 1 Then
				Interlocked.Decrement(_NumberOfThreadsBeganLocking)
				Interlocked.Decrement(_NumberOfThreadsBeganWriting)

				_ThisThreadBeganWriting.Remove(HashCode)
			Else
				_ThisThreadBeganWriting(HashCode) = WriteCount - 1
			End If
		End Sub

		Private Sub IncrementReadLockingCount()
			If _ThisThreadReading Is Nothing Then
				_ThisThreadReading = New Dictionary(Of Integer, Integer)()
			End If

			Dim ReadCount As Integer = 0
			Dim HashCode  As Integer = GetHashCode()

			If _ThisThreadReading.TryGetValue(HashCode, ReadCount) Then
				_ThisThreadReading(HashCode) = ReadCount + 1
			Else
				Interlocked.Increment(_NumberOfThreadsReading)
				Interlocked.Increment(_NumberOfThreadsLocking)

				_ThisThreadReading = New Dictionary(Of Integer, Integer)()
				_ThisThreadReading.Add(HashCode, 1)
			End If
		End Sub

		Private Sub DecrementReadLockingCount()
			Dim HashCode  As Integer = GetHashCode()
			Dim ReadCount As Integer = _ThisThreadReading(HashCode)

			If ReadCount = 1 Then
				Interlocked.Decrement(_NumberOfThreadsLocking)
				Interlocked.Decrement(_NumberOfThreadsReading)

				_ThisThreadReading.Remove(HashCode)
			Else
				_ThisThreadReading(HashCode) = ReadCount - 1
			End If
		End Sub

		Private Sub IncrementWriteLockingCount()
			If _ThisThreadWriting Is Nothing Then
				_ThisThreadWriting = New Dictionary(Of Integer, Integer)()
			End If

			Dim WriteCount As Integer = 0
			Dim HashCode   As Integer = GetHashCode()

			If _ThisThreadWriting.TryGetValue(HashCode, WriteCount) Then
				_ThisThreadWriting(HashCode) = WriteCount + 1
			Else
				Interlocked.Increment(_NumberOfThreadsWriting)
				Interlocked.Increment(_NumberOfThreadsLocking)

				_ThisThreadWriting = New Dictionary(Of Integer, Integer)()
				_ThisThreadWriting.Add(HashCode, 1)
			End If
		End Sub

		Private Sub DecrementWriteLockingCount()
			Dim HashCode   As Integer = GetHashCode()
			Dim WriteCount As Integer = _ThisThreadWriting(HashCode)

			If WriteCount = 1 Then
				Interlocked.Decrement(_NumberOfThreadsLocking)
				Interlocked.Decrement(_NumberOfThreadsWriting)

				_ThisThreadWriting.Remove(HashCode)
			Else
				_ThisThreadWriting(HashCode) = WriteCount - 1
			End If
		End Sub

		Private Sub IncrementSuperThreadCount()
			If Interlocked.CompareExchange(_NumberOfSuperThreads, 1, 0) = 0 Then
				If _ThisThreadSuperThread Is Nothing Then
					_ThisThreadSuperThread = New Dictionary(Of Integer, Integer)()
				End If

				Dim SuperThreadCount As Integer = 0
				Dim HashCode         As Integer = GetHashCode()

				If _ThisThreadSuperThread.TryGetValue(HashCode, SuperThreadCount) Then
					_ThisThreadSuperThread(HashCode) = SuperThreadCount + 1
				Else
					_ThisThreadSuperThread = New Dictionary(Of Integer, Integer)()
					_ThisThreadSuperThread.Add(HashCode, 1)
				End If
			End If
		End Sub

		Private Sub DecrementSuperThreadCount()
			If _ThisThreadSuperThread IsNot Nothing AndAlso _ThisThreadSuperThread.ContainsKey(GetHashCode()) Then
				Dim HashCode         As Integer = GetHashCode()
				Dim SuperThreadCount As Integer = _ThisThreadSuperThread(HashCode)

				If SuperThreadCount = 1 Then
					_ThisThreadSuperThread.Remove(HashCode)
				Else
					Interlocked.Decrement(_NumberOfSuperThreads)
					_ThisThreadSuperThread(HashCode) = SuperThreadCount - 1
				End If
			End If
		End Sub

		#Region "Event Instances"
			Public Event LockedForReading() _
				Implements ISimpleReadWriteLockerEventTracker.LockedForReading
			Public Event UnlockedForReading() _
				Implements ISimpleReadWriteLockerEventTracker.UnlockedForReading

			Public Event LockedForWriting() _
				Implements ISimpleReadWriteLockerEventTracker.LockedForWriting
			Public Event UnlockedForWriting() _
				Implements ISimpleReadWriteLockerEventTracker.UnlockedForWriting
		#End Region

		#Region "Constructor"
			Public Sub New(__behavior As Behavior)
				_Behavior = __behavior
			End Sub
		#End Region

		#Region "Properties"
			#Region "IsThreadSafe"
				Public ReadOnly Property IsThreadSafe As Boolean _
					Implements ISimpleReadWriteLocker.IsThreadSafe

					Get
						Return Not _IsDisposed AndAlso (_Behavior <> Behavior.NoThreadSafety)
					End Get
				End Property
			#End Region

			#Region "IsSuperThreadRunning"
				Public ReadOnly Property IsSuperThreadRunning As Boolean
					Get
						Return Thread.VolatileRead(_NumberOfSuperThreads) > 0
					End Get
				End Property
			#End Region

			#Region "IsReading/IsWriting/IsLocked"
				Public ReadOnly Property IsReading As Boolean _
					Implements ISimpleReadWriteLocker.IsReading

					Get
						Return Thread.VolatileRead(_NumberOfThreadsReading) > 0
					End Get
				End Property

				Public ReadOnly Property IsWriting As Boolean _
					Implements ISimpleReadWriteLocker.IsWriting

					Get
						Return Thread.VolatileRead(_NumberOfThreadsWriting) > 0
					End Get
				End Property

				Public ReadOnly Property IsLocking As Boolean
					Get
						Return Thread.VolatileRead(_NumberOfThreadsLocking) > 0
					End Get
				End Property

				Public ReadOnly Property ReadLockCount As Integer _
					Implements ISimpleReadWriteLockerEventTracker.ReadLockCount

					Get
						Return Thread.VolatileRead(_NumberOfThreadsReading)
					End Get
				End Property

				Public ReadOnly Property WriteLockCount As Integer _
					Implements ISimpleReadWriteLockerEventTracker.WriteLockCount

					Get
						Return Thread.VolatileRead(_NumberOfThreadsWriting)
					End Get
				End Property

				Private ReadOnly Property CurrentThreadReadCount As Integer
					Get
						If _ThisThreadLockedForReading Is Nothing Then
							Return 0
						End If

						Return _ThisThreadLockedForReading(GetHashCode())
					End Get
				End Property

				Private ReadOnly Property CurrentThreadWriteCount As Integer
					Get
						If _ThisThreadLockedForWriting Is Nothing Then
							Return 0
						End If

						Return _ThisThreadLockedForWriting(GetHashCode())
					End Get
				End Property

				Private ReadOnly Property CurrentThreadLockCount As Integer
					Get
						Return CurrentThreadReadCount + CurrentThreadWriteCount
					End Get
				End Property

				Private ReadOnly Property CurrentThreadSuperThreadCount As Integer
					Get
						If _ThisThreadSuperThread Is Nothing Then
							Return 0
						End If

						Return _ThisThreadSuperThread(GetHashCode())
					End Get
				End Property
			#End Region
		#End Region

		#Region "Methods"
			#Region "Threading"
				#Region "IsCurrentThreadLockedFor[Reading/Writing]"
					Public Function IsCurrentThreadLockedForReading() As Boolean _
						Implements IReadWriteLocker.IsCurrentThreadLockedForReading

						Return CurrentThreadReadCount > 0
					End Function

					Public Function IsCurrentThreadLockedForWriting() As Boolean _
						Implements IReadWriteLocker.IsCurrentThreadLockedForWriting

						Return CurrentThreadWriteCount > 0
					End Function

					Public Function IsCurrentThreadLocked() As Boolean
						Return CurrentThreadLockCount > 0
					End Function
				#End Region

				#Region "Begin/End locking, raising appropriate locking event"
					Public Sub LockForReading() _
						Implements IComplexReadWriteLocker.LockForReading

						AddReadLock(False)
						OnLockedForReading()
					End Sub

					Public Sub UnlockForReading() _
						Implements IComplexReadWriteLocker.UnlockForReading

						RemoveReadLock()
						OnUnlockedForReading()
					End Sub					

					Public Sub TryLockForReading() _
						Implements IComplexReadWriteLocker.TryLockForReading

						AddReadLock(True)
						OnLockedForReading()
					End Sub

					Public Sub TryUnlockForReading() _
						Implements IComplexReadWriteLocker.TryUnlockForReading

						UnlockForReading()
						OnUnlockedForReading()
					End Sub

					Public Sub LockForWriting() _
						Implements IComplexReadWriteLocker.LockForWriting

						AddWriteLock(False)
						OnLockedForWriting()
					End Sub

					Public Sub UnlockForWriting() _
						Implements IComplexReadWriteLocker.UnlockForWriting

						RemoveWriteLock()
						OnUnlockedForWriting()
					End Sub

					Public Sub TryLockForWriting() _
						Implements IComplexReadWriteLocker.TryLockForWriting

						AddWriteLock(True)
						OnLockedForWriting()
					End Sub

					Public Sub TryUnlockForWriting() _
						Implements IComplexReadWriteLocker.TryUnlockForWriting

						UnlockForWriting()
						OnUnlockedForWriting()
					End Sub

					Public Sub LockForReadWriting()
						AddWriteLock(False)
						OnLockedForReadWriting()
					End Sub

					Public Sub UnlockForReadWriting()
						RemoveWriteLock()
						OnUnlockedForReadWriting()
					End Sub

					Public Sub TryLockForReadWriting()
						AddWriteLock(True)
						OnLockedForReadWriting()
					End Sub

					Public Sub TryUnlockForReadWriting()
						UnlockForWriting()
						OnUnlockedForReadWriting()
					End Sub
				#End Region

				#Region "External Read/Write Locking"
					''' <summary>
					'''   Gets an object which locks this collection so reading
					'''     can happen multiple times.
					''' </summary>
					''' <remarks>
					'''   If this thread currently has this locked for writing,
					'''     it uses the writelock instead of the readlock.
					'''
					'''   WARNING: If explicitly cast to Object (instead of being IDisposable)
					'''              in Using block, Dispose method will never get called.
					'''              So be careful if Option Explicit is not turned on.
					'''   Example:
					''' 
					'''     ' This never calls IDisposable!
					'''     Using Locker As Object = List.GetReadLock()
					'''       ' Do reading.  Dispose Method will never be called...
					'''     End Using
					''' 
					'''     ' Correct
					'''     Using Locker As List.GetReadLock()
					'''       ' Do reading.
					'''     End Using
					''' </remarks>
					Public Function GetReadLock() As IDisposable     _
						Implements ISimpleReadWriteLocker.GetReadLock

						Return _ReadLockObject.GetLock()
					End Function

					''' <summary>
					'''   Gets an object which locks this collection so writing
					'''     can occur.
					''' </summary>
					''' <remarks>
					'''   If this thread currently has this locked for writing,
					'''     it uses the writelock instead of the readlock.
					'''
					'''   WARNING: If explicitly cast to Object (instead of being IDisposable)
					'''              in Using block, Dispose method will never get called.
					'''              So be careful if Option Explicit is not turned on.
					'''   Example:
					''' 
					'''     ' This never calls IDisposable!
					'''     Using Locker As Object = List.GetWriteLock()
					'''       ' Do Writing.  Dispose Method will never be called...
					'''     End Using
					''' 
					'''     ' Correct
					'''     Using Locker As List.GetWriteLock()
					'''       ' Do Writing.
					'''     End Using
					'''
					'''   Also note that the For Each statement uses a ReaderLock,
					'''     but it is valid to write while reading, so long as no
					'''     other threads are reading as well.
					''' </remarks>
					Public Function GetWriteLock() As IDisposable     _
						Implements ISimpleReadWriteLocker.GetWriteLock, _
						           IReadWriteLocker.GetSyncLock,        _
						           IReadWriteLocker.GetLock

						Return _WriteLockObject.GetLock()
					End Function

					Public Function TryGetReadLock() As IDisposable _
						Implements ISimpleReadWriteLocker.TryGetReadLock

						Return _TryReadLockObject.GetLock()
					End Function

					Public Function TryGetWriteLock() As IDisposable _
						Implements ISimpleReadWriteLocker.TryGetWriteLock

						Return _TryWriteLockObject.GetLock()
					End Function

					''' <summary>
					'''   Alias for GetWriteLock().  This is meant to be used in
					'''     Visual Basic code to replace SyncLock object/End SyncLock.
					''' </summary>
					Public Function GetSyncLock() As IDisposable
						Return GetWriteLock()
					End Function

					''' <summary>
					'''   Alias for getWriteLock().  This is meant to be used in
					'''     C# code to replace lock(object) {}.
					''' </summary>
					''' <returns></returns>
					''' <remarks></remarks>
					Public Function GetLock() As IDisposable
						Return GetWriteLock()
					End Function
				#End Region

				#Region "Locking and Unlocking"
					Private Sub AddReadLock(tryAddReadLock As Boolean)
            IncrementBeganReadLockingCount()

						If (_Behavior <> Behavior.NoThreadSafety AndAlso Not tryAddReadLock) AndAlso AnotherThreadWriting Then
							IncrementEnteredReadLockingCount()

							Dim MultiProcessor As Boolean = Environment.ProcessorCount > 1
							Dim SpinWait       As Integer = 1

							While (AnotherThreadWriting)
									If SpinWait < 11 AndAlso MultiProcessor Then
										Thread.SpinWait(20 * SpinWait)
									ElseIf (SpinWait < 16) Then
											Thread.Sleep(0)
									Else
											Thread.Sleep(1)
									End If

									SpinWait += 1
							End While

							DecrementEnteredReadLockingCount()
						End If

						IncrementReadLockingCount()
					End Sub

					Private Sub RemoveReadLock()
						DecrementReadLockingCount()
						DecrementBeganReadLockingCount()
					End Sub

					''' With tryAddWriteLock = True, there can be more than one write lock...
					Private Sub AddWriteLock(tryAddWriteLock As Boolean)
						IncrementBeganWriteLockingCount()

						If (_Behavior <> Behavior.NoThreadSafety AndAlso Not tryAddWriteLock) AndAlso (OtherThreadsReading OrElse AnotherThreadWriting) Then
							IncrementEnteredWriteLockingCount()

							If Not tryAddWriteLock Then
								Dim MultiProcessor As Boolean = Environment.ProcessorCount > 1
								Dim SpinWait       As Integer = 1

								' Because extra work is being done, spin locking must
								'   not spin as much in NoDeadLocks and ThrowOnDeadLocks.
								If _Behavior = Behavior.NoDeadLocks OrElse _Behavior = Behavior.ThrowOnDeadLocks Then
									While (OtherThreadsReading OrElse AnotherThreadWriting)
										If SpinWait < 11 AndAlso MultiProcessor Then
											Thread.SpinWait(20 * SpinWait)
										ElseIf (SpinWait < 16) Then
											Thread.Sleep(0)
										Else
											If Thread.VolatileRead(_NumberOfSuperThreads) = 0 AndAlso _
												Thread.Equals(_NumberOfThreadsEnteredLocking, _NumberOfThreadsBeganLocking) Then

												' TODO:  Get this to work.  Something doesn't seem to be atomic.
												If SpinWait = 20 Then
													IncrementSuperThreadCount()
												Else
													SpinWait = 11
												End If
											End If

											Thread.Sleep(1)
										End If

										SpinWait += 1
									End While
								Else If _Behavior = Behavior.AllowDeadLocks Then
									While (OtherThreadsReading OrElse AnotherThreadWriting)
										If SpinWait < 11 AndAlso MultiProcessor Then
											Thread.SpinWait(20 * SpinWait)
										ElseIf (SpinWait < 16) Then
												Thread.Sleep(0)
										Else
												Thread.Sleep(1)
										End If

										SpinWait += 1
									End While
								End If
							End If

							DecrementEnteredWriteLockingCount()
						End If

						IncrementWriteLockingCount()

						If _Behavior = Behavior.ThrowOnDeadLocks AndAlso Thread.VolatileRead(_NumberOfSuperThreads) > 0 Then
							Throw New Exception("Deadlock detected")
						End If
					End Sub

					Private Sub RemoveWriteLock()
						DecrementSuperThreadCount()
						DecrementWriteLockingCount()
						DecrementBeganWriteLockingCount()
					End Sub
				#End Region

				#Region "Locking Events"
					' TODO:  Use custom events to track when something handles this event.
					'          Then only call this Overridable Function when something is handling this event.
					Protected Overridable Sub OnLockedForReading()
						RaiseEvent LockedForReading()
					End Sub

					' TODO:  Use custom events to track when something handles this event.
					'          Then only call this Overridable Function when something is handling this event.
					Protected Overridable Sub OnLockedForWriting()
						RaiseEvent LockedForWriting()
					End Sub

					' TODO:  Use custom events to track when something handles this event.
					'          Then only call this Overridable Function when something is handling this event.
					Protected Overridable Sub OnLockedForReadWriting()
						RaiseEvent LockedForReading()
						RaiseEvent LockedForWriting()
					End Sub

					' TODO:  Use custom events to track when something handles this event.
					'          Then only call this Overridable Function when something is handling this event.
					Protected Overridable Sub OnUnlockedForReading()
						RaiseEvent UnlockedForReading()
					End Sub

					' TODO:  Use custom events to track when something handles this event.
					'          Then only call this Overridable Function when something is handling this event.
					Protected Overridable Sub OnUnlockedForWriting()
						RaiseEvent UnlockedForWriting()
					End Sub

					' TODO:  Use custom events to track when something handles this event.
					'          Then only call this Overridable Function when something is handling this event.
					Protected Overridable Sub OnUnlockedForReadWriting()
						RaiseEvent UnlockedForReading()
						RaiseEvent UnlockedForWriting()
					End Sub
				#End Region
			#End Region

			#Region "IDisposable"
				' IDisposable
				Protected Overridable Sub Dispose(disposing As Boolean)
					If Not _IsDisposed Then
						_IsDisposed = True
					End If
				End Sub

				#Region " IDisposable Support "
					' This code added by Visual Basic to correctly implement the disposable pattern.
					Public Sub Dispose() _
						Implements IDisposable.Dispose

						'' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
						Dispose(True)
						GC.SuppressFinalize(Me)
					End Sub

					' Makes sure that the Global Hard-Lock Tracking has this removed from it.
					Protected Overrides Sub Finalize()
						Dispose(False)
					End Sub
				#End Region
			#End Region
		#End Region
	End Class
#End Region
